public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v11 00/40] Optimize type traits performance
@ 2023-09-14  6:42 Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
                   ` (40 more replies)
  0 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++. This patch version
is bumped from the highest version among my separated patches.

Changes in v11:

	* Merge all patches into one patch series
	* Rebase on top of trunk
	* Unify commit message style
	* Use _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (40):
  c++: Sort built-in identifiers alphabetically
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c, c++: Use 16 bits for all use of enum rid for more keyword space
  c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.h                       |   2 +-
 gcc/c-family/c-indentation.h                  |   2 +-
 gcc/c/c-parser.cc                             |   6 +-
 gcc/c/c-parser.h                              |   6 +-
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/parser.h                               |   8 +-
 gcc/cp/semantics.cc                           | 149 ++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 ++++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libcpp/include/cpplib.h                       |   2 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 ++++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 42 files changed, 1343 insertions(+), 249 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 01/40] c++: Sort built-in identifiers alphabetically
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 02/40] c++: Implement __is_const built-in trait Ken Matsui
                   ` (39 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 +++++++++----------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 86 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++----------
 4 files changed, 117 insertions(+), 117 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..ce3733df641 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..7d0240edcc0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12075,15 +12075,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12092,17 +12083,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12116,18 +12116,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12136,6 +12139,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12151,6 +12160,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12181,24 +12199,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12357,8 +12357,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12421,25 +12421,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 02/40] c++: Implement __is_const built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ce3733df641..a4ebfd9f319 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7d0240edcc0..baeda9f03e9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12356,6 +12359,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 03/40] libstdc++: Optimize is_const trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 02/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
                   ` (37 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 04/40] c++: Implement __is_volatile built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (2 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index a4ebfd9f319..60462cd9874 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index baeda9f03e9..18390f530ee 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12363,6 +12366,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 05/40] libstdc++: Optimize is_volatile trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (3 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 06/40] c++: Implement __is_array built-in trait Ken Matsui
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 06/40] c++: Implement __is_array built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (4 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 60462cd9874..c9106242bc8 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 18390f530ee..562b0bb8438 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12361,6 +12364,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 07/40] libstdc++: Optimize is_array trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (5 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 06/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 08/40] c++: Implement __is_unbounded_array built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (6 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c9106242bc8..1e67a3d2089 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 562b0bb8438..4fdec0c30c1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12369,6 +12372,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 09/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (7 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 10/40] c++: Implement __is_bounded_array built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (8 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1e67a3d2089..b6146c010f6 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4fdec0c30c1..bf6438fcfc5 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12368,6 +12371,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 11/40] libstdc++: Optimize is_bounded_array trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (9 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 12/40] c++: Implement __is_scoped_enum built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (10 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b6146c010f6..047307c95ce 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bf6438fcfc5..7f89616aa03 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12190,6 +12190,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 13/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (11 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 14/40] c++: Implement __is_member_pointer built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (12 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 047307c95ce..7fed3483221 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7f89616aa03..84291d660ce 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 15/40] libstdc++: Optimize is_member_pointer trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (13 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (14 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14 17:53   ` Joseph Myers
  2023-09-14  6:42 ` [PATCH v11 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
                   ` (24 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Now that RID_MAX has reached 255, we need to update the bit sizes of every
use of the enum rid from 8 to 16 to support more keywords.

gcc/c-family/ChangeLog:

	* c-indentation.h (struct token_indent_info): Make keyword 16 bits
	and move this upward to minimize memory fragmentation.

gcc/c/ChangeLog:

	* c-parser.cc (c_parse_init): Handle RID_MAX not to exceed the max
	value of 16 bits.
	* c-parser.h (struct c_token): Make keyword 16 bits and move this
	upward to minimize memory fragmentation.

gcc/cp/ChangeLog:

	* parser.h (struct cp_token): Make keyword 16 bits and move this
	upward to minimize memory fragmentation.
	(struct cp_lexer): Likewise, for saved_keyword.

libcpp/ChangeLog:

	* include/cpplib.h (struct cpp_hashnode): Make rid_code 16 bits.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-indentation.h | 2 +-
 gcc/c/c-parser.cc            | 6 +++---
 gcc/c/c-parser.h             | 6 +++---
 gcc/cp/parser.h              | 8 ++++----
 libcpp/include/cpplib.h      | 2 +-
 5 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index c0e07bf49f1..1ce8753813a 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -25,8 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 struct token_indent_info
 {
   location_t location;
+  ENUM_BITFIELD (rid) keyword : 16;
   ENUM_BITFIELD (cpp_ttype) type : 8;
-  ENUM_BITFIELD (rid) keyword : 8;
 };
 
 /* Extract token information from TOKEN, which ought to either be a
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b9a1b75ca43..2086f253923 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -115,9 +115,9 @@ c_parse_init (void)
   tree id;
   int mask = 0;
 
-  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
-     the c_token structure.  */
-  gcc_assert (RID_MAX <= 255);
+  /* Make sure RID_MAX hasn't grown past the 16 bits used to hold the keyword
+     in the c_token structure.  */
+  gcc_assert (RID_MAX <= 65535);
 
   mask |= D_CXXONLY;
   if (!flag_isoc99)
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 545f0f4d9eb..eed6deaf0f8 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -51,14 +51,14 @@ enum c_id_kind {
 /* A single C token after string literal concatenation and conversion
    of preprocessing tokens to tokens.  */
 struct GTY (()) c_token {
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 16;
   /* The kind of token.  */
   ENUM_BITFIELD (cpp_ttype) type : 8;
   /* If this token is a CPP_NAME, this value indicates whether also
      declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
   ENUM_BITFIELD (c_id_kind) id_kind : 8;
-  /* If this token is a keyword, this value indicates which keyword.
-     Otherwise, this value is RID_MAX.  */
-  ENUM_BITFIELD (rid) keyword : 8;
   /* If this token is a CPP_PRAGMA, this indicates the pragma that
      was seen.  Otherwise it is PRAGMA_NONE.  */
   ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6cbb9a8e031..3c3c482c6ce 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -40,11 +40,11 @@ struct GTY(()) tree_check {
 /* A C++ token.  */
 
 struct GTY (()) cp_token {
-  /* The kind of token.  */
-  enum cpp_ttype type : 8;
   /* If this token is a keyword, this value indicates which keyword.
      Otherwise, this value is RID_MAX.  */
-  enum rid keyword : 8;
+  enum rid keyword : 16;
+  /* The kind of token.  */
+  enum cpp_ttype type : 8;
   /* Token flags.  */
   unsigned char flags;
   /* True if this token is from a context where it is implicitly extern "C" */
@@ -101,8 +101,8 @@ struct GTY (()) cp_lexer {
   vec<cp_token_position> GTY ((skip)) saved_tokens;
 
   /* Saved pieces of end token we replaced with the eof token.  */
+  enum rid saved_keyword : 16;
   enum cpp_ttype saved_type : 8;
-  enum rid saved_keyword : 8;
 
   /* The next lexer in a linked list of lexers.  */
   struct cp_lexer *next;
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index fcdaf082b09..b93899cd364 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -988,7 +988,7 @@ struct GTY(()) cpp_hashnode {
   unsigned int directive_index : 7;	/* If is_directive,
 					   then index into directive table.
 					   Otherwise, a NODE_OPERATOR.  */
-  unsigned int rid_code : 8;		/* Rid code - for front ends.  */
+  unsigned int rid_code : 16;		/* Rid code - for front ends.  */
   unsigned int flags : 9;		/* CPP flags.  */
   ENUM_BITFIELD(node_type) type : 2;	/* CPP node type.  */
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (15 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Andrew Pinski

This patch fixes incorrect handling for the new 16-bit rid code. Unsigned
char was previously used for the 8-bit rid code, but unsigned short is now
required.

gcc/c-family/ChangeLog:

	* c-common.h (C_SET_RID_CODE): Use unsigned short instead of
	unsigned char.

Ref: Initial discussion: https://gcc.gnu.org/pipermail/gcc/2023-September/242460.html
     Code provided by Andrew: https://gcc.gnu.org/pipermail/gcc/2023-September/242461.html
Co-authored-by: Andrew Pinski <pinskia@gmail.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..73bc23fa49f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -382,7 +382,7 @@ enum c_tree_index
 #define C_RID_CODE(id) \
   ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code))
 #define C_SET_RID_CODE(id, code) \
-  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code)
+  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned short) code)
 
 /* Identifier part common to the C front ends.  Inherits from
    tree_identifier, despite appearances.  */
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (16 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 7fed3483221..6ebe3984d17 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 84291d660ce..294bcf3dcca 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12381,6 +12384,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (17 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:42 ` [PATCH v11 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (18 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-09-14  6:42 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6ebe3984d17..47649150ab5 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 294bcf3dcca..534f24a1f9c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12172,6 +12172,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12385,6 +12388,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (19 preceding siblings ...)
  2023-09-14  6:42 ` [PATCH v11 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 22/40] c++: Implement __is_reference built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (20 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 47649150ab5..ac9fa026b4e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 534f24a1f9c..97ec53a7606 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 23/40] libstdc++: Optimize is_reference trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (21 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 24/40] c++: Implement __is_function built-in trait Ken Matsui
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 24/40] c++: Implement __is_function built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (22 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ac9fa026b4e..3bb33a3d5c0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 97ec53a7606..7457475f646 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12163,6 +12163,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 25/40] libstdc++: Optimize is_function trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (23 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 26/40] libstdc++: Optimize is_object " Ken Matsui
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 26/40] libstdc++: Optimize is_object trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (24 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 27/40] c++: Implement __remove_pointer built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (25 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 3bb33a3d5c0..07cd14b6e85 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7457475f646..4de2dbbf603 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12473,6 +12473,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (26 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 29/40] c++, libstdc++: Implement __is_pointer built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (27 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C       | 51 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 22 ++++-----
 gcc/testsuite/g++.dg/torture/20070621-1.C   |  4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  6 +--
 libstdc++-v3/include/bits/deque.tcc         |  6 +--
 libstdc++-v3/include/bits/stl_algobase.h    |  6 +--
 11 files changed, 86 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 07cd14b6e85..bc2bb5e5abb 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4de2dbbf603..4b73863ec77 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12397,6 +12400,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 30/40] libstdc++: Optimize is_pointer trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (28 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (29 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_arithmetic.C    | 33 ++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  6 +--
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  4 +-
 libstdc++-v3/include/c_global/cmath         | 48 ++++++++++-----------
 libstdc++-v3/include/c_std/cmath            | 24 +++++------
 libstdc++-v3/include/tr1/cmath              | 24 +++++------
 11 files changed, 99 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index bc2bb5e5abb..06c203ce4de 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b73863ec77..351f453356f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (30 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (31 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 34/40] libstdc++: Optimize is_compound " Ken Matsui
                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 34/40] libstdc++: Optimize is_compound trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (32 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 35/40] c++: Implement __is_unsigned built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (33 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unsigned.C   | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 06c203ce4de..611e84cbbfd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 351f453356f..74bfd5f0961 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12235,6 +12235,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (34 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 37/40] c++, libstdc++: Implement __is_signed built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (35 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_signed.C         | 47 ++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C            | 12 ++---
 libstdc++-v3/include/bits/charconv.h         |  2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |  6 +--
 libstdc++-v3/include/bits/uniform_int_dist.h |  4 +-
 libstdc++-v3/include/ext/numeric_traits.h    | 18 ++++----
 10 files changed, 79 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 611e84cbbfd..f0b5fe9cb3b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 74bfd5f0961..f5aa78adf16 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 38/40] libstdc++: Optimize is_signed trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (36 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 39/40] c++, libstdc++: Implement __is_scalar built-in trait
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (37 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-14  6:43 ` [PATCH v11 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scalar.C        | 31 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 10 +++----
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +--
 libstdc++-v3/include/bits/cpp_type_traits.h |  2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |  8 +++---
 libstdc++-v3/include/bits/valarray_array.h  |  2 +-
 10 files changed, 55 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index f0b5fe9cb3b..4e220262020 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f5aa78adf16..91631c211ab 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12413,6 +12416,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v11 40/40] libstdc++: Optimize is_scalar trait performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (38 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-09-14  6:43 ` Ken Matsui
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-14  6:42 ` [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-14 17:53   ` Joseph Myers
  2023-09-14 21:44     ` Ken Matsui
  2023-09-15 23:26     ` Ken Matsui
  0 siblings, 2 replies; 623+ messages in thread
From: Joseph Myers @ 2023-09-14 17:53 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Wed, 13 Sep 2023, Ken Matsui via Gcc-patches wrote:

> diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
> index 545f0f4d9eb..eed6deaf0f8 100644
> --- a/gcc/c/c-parser.h
> +++ b/gcc/c/c-parser.h
> @@ -51,14 +51,14 @@ enum c_id_kind {
>  /* A single C token after string literal concatenation and conversion
>     of preprocessing tokens to tokens.  */
>  struct GTY (()) c_token {
> +  /* If this token is a keyword, this value indicates which keyword.
> +     Otherwise, this value is RID_MAX.  */
> +  ENUM_BITFIELD (rid) keyword : 16;
>    /* The kind of token.  */
>    ENUM_BITFIELD (cpp_ttype) type : 8;
>    /* If this token is a CPP_NAME, this value indicates whether also
>       declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
>    ENUM_BITFIELD (c_id_kind) id_kind : 8;
> -  /* If this token is a keyword, this value indicates which keyword.
> -     Otherwise, this value is RID_MAX.  */
> -  ENUM_BITFIELD (rid) keyword : 8;
>    /* If this token is a CPP_PRAGMA, this indicates the pragma that
>       was seen.  Otherwise it is PRAGMA_NONE.  */
>    ENUM_BITFIELD (pragma_kind) pragma_kind : 8;

If you want to optimize layout, I'd expect flags to move so it can share 
the same 32-bit unit as the pragma_kind bit-field (not sure if any changes 
should be made to the declaration of flags to maximise the chance of such 
sharing across different host bit-field ABIs).

> diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
> index 6cbb9a8e031..3c3c482c6ce 100644
> --- a/gcc/cp/parser.h
> +++ b/gcc/cp/parser.h
> @@ -40,11 +40,11 @@ struct GTY(()) tree_check {
>  /* A C++ token.  */
>  
>  struct GTY (()) cp_token {
> -  /* The kind of token.  */
> -  enum cpp_ttype type : 8;
>    /* If this token is a keyword, this value indicates which keyword.
>       Otherwise, this value is RID_MAX.  */
> -  enum rid keyword : 8;
> +  enum rid keyword : 16;
> +  /* The kind of token.  */
> +  enum cpp_ttype type : 8;
>    /* Token flags.  */
>    unsigned char flags;
>    /* True if this token is from a context where it is implicitly extern "C" */

You're missing an update to the "3 unused bits." comment further down.

> @@ -988,7 +988,7 @@ struct GTY(()) cpp_hashnode {
>    unsigned int directive_index : 7;	/* If is_directive,
>  					   then index into directive table.
>  					   Otherwise, a NODE_OPERATOR.  */
> -  unsigned int rid_code : 8;		/* Rid code - for front ends.  */
> +  unsigned int rid_code : 16;		/* Rid code - for front ends.  */
>    unsigned int flags : 9;		/* CPP flags.  */
>    ENUM_BITFIELD(node_type) type : 2;	/* CPP node type.  */

You're missing an update to the "5 bits spare." comment further down.

Do you have any figures for the effects on compilation time or memory 
usage from the increase in size of these structures?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-14 17:53   ` Joseph Myers
@ 2023-09-14 21:44     ` Ken Matsui
  2023-09-15 23:26     ` Ken Matsui
  1 sibling, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-14 21:44 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Ken Matsui, gcc-patches, libstdc++

On Thu, Sep 14, 2023 at 10:54 AM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Wed, 13 Sep 2023, Ken Matsui via Gcc-patches wrote:
>
> > diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
> > index 545f0f4d9eb..eed6deaf0f8 100644
> > --- a/gcc/c/c-parser.h
> > +++ b/gcc/c/c-parser.h
> > @@ -51,14 +51,14 @@ enum c_id_kind {
> >  /* A single C token after string literal concatenation and conversion
> >     of preprocessing tokens to tokens.  */
> >  struct GTY (()) c_token {
> > +  /* If this token is a keyword, this value indicates which keyword.
> > +     Otherwise, this value is RID_MAX.  */
> > +  ENUM_BITFIELD (rid) keyword : 16;
> >    /* The kind of token.  */
> >    ENUM_BITFIELD (cpp_ttype) type : 8;
> >    /* If this token is a CPP_NAME, this value indicates whether also
> >       declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
> >    ENUM_BITFIELD (c_id_kind) id_kind : 8;
> > -  /* If this token is a keyword, this value indicates which keyword.
> > -     Otherwise, this value is RID_MAX.  */
> > -  ENUM_BITFIELD (rid) keyword : 8;
> >    /* If this token is a CPP_PRAGMA, this indicates the pragma that
> >       was seen.  Otherwise it is PRAGMA_NONE.  */
> >    ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
>
> If you want to optimize layout, I'd expect flags to move so it can share
> the same 32-bit unit as the pragma_kind bit-field (not sure if any changes
> should be made to the declaration of flags to maximise the chance of such
> sharing across different host bit-field ABIs).
>

Thank you for your review!

I did not make this change aggressively, but we can do the following
to minimize the fragmentation:

struct GTY (()) c_token {
  tree value; /* pointer, depends, but 4 or 8 bytes as usual */
  location_t location; /* unsigned int, at least 2 bytes, 4 bytes as usual */
  ENUM_BITFIELD (rid) keyword : 16; /* 2 bytes */
  ENUM_BITFIELD (cpp_ttype) type : 8; /* 1 byte */
  ENUM_BITFIELD (c_id_kind) id_kind : 8; /* 1 byte */
  ENUM_BITFIELD (pragma_kind) pragma_kind : 8; /* 1 byte */
  unsigned char flags; /* 1 byte */
}

Supposing a pointer size is 8 bytes and int is 4 bytes, the struct
size would be 24 bytes. The internal fragmentation would be 0 bytes,
and the external fragmentation is 6 bytes since the overall struct
alignment requirement is $K_{max} = 8$ from the pointer.

Here is the original struct before making keyword 16-bit. The overall
struct alignment requirement is $K_{max} = 8$ from the pointer. This
struct size would be 24 bytes since the internal fragmentation is 4
bytes (after location), and the external fragmentation is 3 bytes.

struct GTY (()) c_token {
  ENUM_BITFIELD (cpp_ttype) type : 8; /* 1 byte */
  ENUM_BITFIELD (c_id_kind) id_kind : 8; /* 1 byte */
  ENUM_BITFIELD (rid) keyword : 8; /* 1 byte */
  ENUM_BITFIELD (pragma_kind) pragma_kind : 8; /* 1 byte */
  location_t location; /* unsigned int, at least 2 bytes, 4 bytes as usual */
  tree value; /* pointer, depends, but 4 or 8 bytes as usual */
  unsigned char flags; /* 1 byte */
}

If we keep the original order with the 16-bit keyword, the struct size
would be 32 bytes (my current implementation as well, I will update
this patch).

struct GTY (()) c_token {
  ENUM_BITFIELD (cpp_ttype) type : 8; /* 1 byte */
  ENUM_BITFIELD (c_id_kind) id_kind : 8; /* 1 byte */
  ENUM_BITFIELD (rid) keyword : 16; /* 2 bytes */
  ENUM_BITFIELD (pragma_kind) pragma_kind : 8; /* 1 byte */
  location_t location; /* unsigned int, at least 2 bytes, 4 bytes as usual */
  tree value; /* pointer, depends, but 4 or 8 bytes as usual */
  unsigned char flags; /* 1 byte */
}

Likewise, the overall struct alignment requirement is $K_{max} = 8$
from the pointer. The internal fragmentation would be 7 bytes (3 bytes
after pragma_kind + 4 bytes after location), and the external
fragmentation would be 7 bytes.

I think optimizing the size is worth doing unless this breaks GCC.

> > diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
> > index 6cbb9a8e031..3c3c482c6ce 100644
> > --- a/gcc/cp/parser.h
> > +++ b/gcc/cp/parser.h
> > @@ -40,11 +40,11 @@ struct GTY(()) tree_check {
> >  /* A C++ token.  */
> >
> >  struct GTY (()) cp_token {
> > -  /* The kind of token.  */
> > -  enum cpp_ttype type : 8;
> >    /* If this token is a keyword, this value indicates which keyword.
> >       Otherwise, this value is RID_MAX.  */
> > -  enum rid keyword : 8;
> > +  enum rid keyword : 16;
> > +  /* The kind of token.  */
> > +  enum cpp_ttype type : 8;
> >    /* Token flags.  */
> >    unsigned char flags;
> >    /* True if this token is from a context where it is implicitly extern "C" */
>
> You're missing an update to the "3 unused bits." comment further down.
>
> > @@ -988,7 +988,7 @@ struct GTY(()) cpp_hashnode {
> >    unsigned int directive_index : 7;  /* If is_directive,
> >                                          then index into directive table.
> >                                          Otherwise, a NODE_OPERATOR.  */
> > -  unsigned int rid_code : 8;         /* Rid code - for front ends.  */
> > +  unsigned int rid_code : 16;                /* Rid code - for front ends.  */
> >    unsigned int flags : 9;            /* CPP flags.  */
> >    ENUM_BITFIELD(node_type) type : 2; /* CPP node type.  */
>
> You're missing an update to the "5 bits spare." comment further down.
>

Thank you!

> Do you have any figures for the effects on compilation time or memory
> usage from the increase in size of these structures?
>

Regarding only c_token, we will have the same size if we optimize the
size. Although I did not calculate the size of other structs, we might
not see any significant performance change? I am taking benchmarks and
will let you know once it is done.


> --
> Joseph S. Myers
> joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 00/40] Optimize type traits performance
  2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
                   ` (39 preceding siblings ...)
  2023-09-14  6:43 ` [PATCH v11 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-09-15  2:21 ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
                     ` (40 more replies)
  40 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (40):
  c++: Sort built-in identifiers alphabetically
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c, c++: Use 16 bits for all use of enum rid for more keyword space
  c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.h                       |   2 +-
 gcc/c-family/c-indentation.h                  |   2 +-
 gcc/c/c-parser.cc                             |   6 +-
 gcc/c/c-parser.h                              |  14 +-
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/parser.h                               |   8 +-
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 ++++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libcpp/include/cpplib.h                       |   7 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 ++++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 42 files changed, 1356 insertions(+), 257 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 01/40] c++: Sort built-in identifiers alphabetically
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 02/40] c++: Implement __is_const built-in trait Ken Matsui
                     ` (39 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..ce3733df641 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..92f4f3fd4f6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12075,15 +12075,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12092,17 +12083,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12116,18 +12116,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12136,6 +12139,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12151,6 +12160,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12181,24 +12199,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12311,9 +12311,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12333,12 +12333,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12357,8 +12357,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12421,25 +12421,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 02/40] c++: Implement __is_const built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
                     ` (38 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ce3733df641..a4ebfd9f319 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 92f4f3fd4f6..17d6e6728f9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12356,6 +12359,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 03/40] libstdc++: Optimize is_const trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 02/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
                     ` (37 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 04/40] c++: Implement __is_volatile built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (2 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                     ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index a4ebfd9f319..60462cd9874 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 17d6e6728f9..647124265a6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12363,6 +12366,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 05/40] libstdc++: Optimize is_volatile trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (3 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 06/40] c++: Implement __is_array built-in trait Ken Matsui
                     ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 06/40] c++: Implement __is_array built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (4 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
                     ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 60462cd9874..c9106242bc8 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 647124265a6..8d5d443d9a9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12361,6 +12364,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 07/40] libstdc++: Optimize is_array trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (5 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 06/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                     ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 08/40] c++: Implement __is_unbounded_array built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (6 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                     ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c9106242bc8..1e67a3d2089 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5d443d9a9..fd7bdf7a293 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12369,6 +12372,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 09/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (7 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                     ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 10/40] c++: Implement __is_bounded_array built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (8 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                     ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1e67a3d2089..b6146c010f6 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index fd7bdf7a293..605cf03c18d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12368,6 +12371,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 11/40] libstdc++: Optimize is_bounded_array trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (9 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                     ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 12/40] c++: Implement __is_scoped_enum built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (10 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                     ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b6146c010f6..047307c95ce 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 605cf03c18d..c971c34cf6f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12190,6 +12190,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 13/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (11 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                     ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 14/40] c++: Implement __is_member_pointer built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (12 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                     ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 047307c95ce..7fed3483221 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c971c34cf6f..7091e581ac7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 15/40] libstdc++: Optimize is_member_pointer trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (13 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
                     ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (14 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
                     ` (24 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Now that RID_MAX has reached 255, we need to update the bit sizes of every
use of the enum rid from 8 to 16 to support more keywords.

For struct token_indent_info, the 8-bit increase does not change the overall
struct size because the 8-bit just consumes 1 byte from 2 bytes of external
fragmentation.  Since reordering the fields just changes 1 byte of internal
fragmentation to 1 byte of external fragmentation, I keep the original field
order.

For struct c_token, the 8-bit expansion increased the overall struct size from
24 bytes to 32 bytes.  The original struct takes 4 bytes of internal
fragmentation (after the location field) and 3 bytes of external
fragmentation.  Keeping the original order with the 8-bit expansion gives
7 bytes of internal fragmentation (3 bytes after the pragma_kind field + 4
bytes after the location field) and 7 bytes of external fragmentation. Since
the original field order was not optimal, reordering the fields results in the
same overall size as the original one.

For struct cp_token, reordering the fields only minimizes internal
fragmentation and does not minimize the overall struct size.  I keep the
original field order. The original struct size was 16 bytes with 3 bits of
internal fragmentation.  With this 8-bit update, the overall size would be
24 bytes.  Since there is no external fragmentation and 7 bytes + 3 bits of
internal fragmentation, reordering the fields does not minimize the overall
size.  I keep the orignal field order.

Suppose a pointer takes 8 bytes and int takes 4 bytes. Then, struct
ht_identifier takes 16 bytes, and union _cpp_hashnode_value takes 8 bytes.
For struct cpp_hashnode, the 8-bit increase consumes 1 more byte, resulting in
33 bytes except for paddings.  The original overall size before the 8-bit
increase was 32 bytes.  However, due to fragmentation, the overall struct size
would be 40 bytes.  Since there is no external fragmentation and 3 bytes + 5
bits of internal fragmentation, reordering the fields does not minimize the
overall size.  I keep the original field order.

gcc/c-family/ChangeLog:

	* c-indentation.h (struct token_indent_info): Make keyword 16 bits.

gcc/c/ChangeLog:

	* c-parser.cc (c_parse_init): Handle RID_MAX not to exceed the max
	value of 16 bits.
	* c-parser.h (struct c_token): Make keyword 16 bits. Reorder the
	fields to minimize memory fragmentation.

gcc/cp/ChangeLog:

	* parser.h (struct cp_token): Make keyword 16 bits.
	(struct cp_lexer): Make saved_keyword 16 bits.

libcpp/ChangeLog:

	* include/cpplib.h (struct cpp_hashnode): Make rid_code 16 bits.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-indentation.h |  2 +-
 gcc/c/c-parser.cc            |  6 +++---
 gcc/c/c-parser.h             | 14 +++++++-------
 gcc/cp/parser.h              |  8 +++++---
 libcpp/include/cpplib.h      |  7 +++++--
 5 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index c0e07bf49f1..6d2b88f01a3 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -26,7 +26,7 @@ struct token_indent_info
 {
   location_t location;
   ENUM_BITFIELD (cpp_ttype) type : 8;
-  ENUM_BITFIELD (rid) keyword : 8;
+  ENUM_BITFIELD (rid) keyword : 16;
 };
 
 /* Extract token information from TOKEN, which ought to either be a
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b9a1b75ca43..2086f253923 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -115,9 +115,9 @@ c_parse_init (void)
   tree id;
   int mask = 0;
 
-  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
-     the c_token structure.  */
-  gcc_assert (RID_MAX <= 255);
+  /* Make sure RID_MAX hasn't grown past the 16 bits used to hold the keyword
+     in the c_token structure.  */
+  gcc_assert (RID_MAX <= 65535);
 
   mask |= D_CXXONLY;
   if (!flag_isoc99)
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 545f0f4d9eb..6a9bd22a793 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -51,21 +51,21 @@ enum c_id_kind {
 /* A single C token after string literal concatenation and conversion
    of preprocessing tokens to tokens.  */
 struct GTY (()) c_token {
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* The location at which this token was found.  */
+  location_t location;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 16;
   /* The kind of token.  */
   ENUM_BITFIELD (cpp_ttype) type : 8;
   /* If this token is a CPP_NAME, this value indicates whether also
      declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
   ENUM_BITFIELD (c_id_kind) id_kind : 8;
-  /* If this token is a keyword, this value indicates which keyword.
-     Otherwise, this value is RID_MAX.  */
-  ENUM_BITFIELD (rid) keyword : 8;
   /* If this token is a CPP_PRAGMA, this indicates the pragma that
      was seen.  Otherwise it is PRAGMA_NONE.  */
   ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
-  /* The location at which this token was found.  */
-  location_t location;
-  /* The value associated with this token, if any.  */
-  tree value;
   /* Token flags.  */
   unsigned char flags;
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6cbb9a8e031..7aa251d11b1 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -44,7 +44,7 @@ struct GTY (()) cp_token {
   enum cpp_ttype type : 8;
   /* If this token is a keyword, this value indicates which keyword.
      Otherwise, this value is RID_MAX.  */
-  enum rid keyword : 8;
+  enum rid keyword : 16;
   /* Token flags.  */
   unsigned char flags;
   /* True if this token is from a context where it is implicitly extern "C" */
@@ -59,7 +59,9 @@ struct GTY (()) cp_token {
   bool purged_p : 1;
   bool tree_check_p : 1;
   bool main_source_p : 1;
-  /* 3 unused bits.  */
+  /* These booleans use 5 bits within 1 byte, resulting in 3 unused bits.
+     Since there would be 3 bytes of internal fragmentation to the location
+     field, the total unused bits would be 27 (= 3 + 24).  */
 
   /* The location at which this token was found.  */
   location_t location;
@@ -102,7 +104,7 @@ struct GTY (()) cp_lexer {
 
   /* Saved pieces of end token we replaced with the eof token.  */
   enum cpp_ttype saved_type : 8;
-  enum rid saved_keyword : 8;
+  enum rid saved_keyword : 16;
 
   /* The next lexer in a linked list of lexers.  */
   struct cp_lexer *next;
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index fcdaf082b09..389f8cfb1f6 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -988,11 +988,14 @@ struct GTY(()) cpp_hashnode {
   unsigned int directive_index : 7;	/* If is_directive,
 					   then index into directive table.
 					   Otherwise, a NODE_OPERATOR.  */
-  unsigned int rid_code : 8;		/* Rid code - for front ends.  */
+  unsigned int rid_code : 16;		/* Rid code - for front ends.  */
   unsigned int flags : 9;		/* CPP flags.  */
   ENUM_BITFIELD(node_type) type : 2;	/* CPP node type.  */
 
-  /* 5 bits spare.  */
+  /* Bitfields use 35 bits (= 1 + 7 + 16 + 9 + 2).  The exceeded 3 bits in
+     terms of bytes leave 5 unused bits within 1 byte.  Since there would be
+     3 bytes of internal fragmentation to the deferred field, the total unused
+     bits would be 29 (= 5 + 24).  */
 
   /* The deferred cookie is applicable to NT_USER_MACRO or NT_VOID.
      The latter for when a macro had a prevailing undef.
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (15 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                     ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Andrew Pinski

This patch fixes incorrect handling for the new 16-bit rid code. Unsigned
char was previously used for the 8-bit rid code, but unsigned short is now
required.

gcc/c-family/ChangeLog:

	* c-common.h (C_SET_RID_CODE): Use unsigned short instead of
	unsigned char.

Ref: Initial discussion: https://gcc.gnu.org/pipermail/gcc/2023-September/242460.html
     Code provided by Andrew: https://gcc.gnu.org/pipermail/gcc/2023-September/242461.html
Co-authored-by: Andrew Pinski <pinskia@gmail.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..73bc23fa49f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -382,7 +382,7 @@ enum c_tree_index
 #define C_RID_CODE(id) \
   ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code))
 #define C_SET_RID_CODE(id, code) \
-  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code)
+  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned short) code)
 
 /* Identifier part common to the C front ends.  Inherits from
    tree_identifier, despite appearances.  */
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (16 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                     ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 7fed3483221..6ebe3984d17 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7091e581ac7..93e166923b8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12381,6 +12384,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (17 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                     ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (18 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                     ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6ebe3984d17..47649150ab5 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 93e166923b8..95b25c1348b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12172,6 +12172,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12385,6 +12388,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (19 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                     ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 22/40] c++: Implement __is_reference built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (20 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                     ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 47649150ab5..ac9fa026b4e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 95b25c1348b..bee27b25974 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 23/40] libstdc++: Optimize is_reference trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (21 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 24/40] c++: Implement __is_function built-in trait Ken Matsui
                     ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 24/40] c++: Implement __is_function built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (22 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                     ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ac9fa026b4e..3bb33a3d5c0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bee27b25974..a502c13ecc1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12163,6 +12163,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 25/40] libstdc++: Optimize is_function trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (23 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 26/40] libstdc++: Optimize is_object " Ken Matsui
                     ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 26/40] libstdc++: Optimize is_object trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (24 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                     ` (14 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 27/40] c++: Implement __remove_pointer built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (25 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                     ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 3bb33a3d5c0..07cd14b6e85 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a502c13ecc1..10656017bbc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12473,6 +12473,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (26 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                     ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 29/40] c++, libstdc++: Implement __is_pointer built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (27 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                     ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C       | 51 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 22 ++++-----
 gcc/testsuite/g++.dg/torture/20070621-1.C   |  4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  6 +--
 libstdc++-v3/include/bits/deque.tcc         |  6 +--
 libstdc++-v3/include/bits/stl_algobase.h    |  6 +--
 11 files changed, 86 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 07cd14b6e85..bc2bb5e5abb 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 10656017bbc..131ca8b96e6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12397,6 +12400,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 30/40] libstdc++: Optimize is_pointer trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (28 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                     ` (10 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (29 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                     ` (9 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_arithmetic.C    | 33 ++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  6 +--
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  4 +-
 libstdc++-v3/include/c_global/cmath         | 48 ++++++++++-----------
 libstdc++-v3/include/c_std/cmath            | 24 +++++------
 libstdc++-v3/include/tr1/cmath              | 24 +++++------
 11 files changed, 99 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index bc2bb5e5abb..06c203ce4de 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 131ca8b96e6..553a51dc16d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (30 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                     ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (31 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 34/40] libstdc++: Optimize is_compound " Ken Matsui
                     ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 34/40] libstdc++: Optimize is_compound trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (32 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                     ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 35/40] c++: Implement __is_unsigned built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (33 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                     ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unsigned.C   | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 06c203ce4de..611e84cbbfd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 553a51dc16d..b5c6b4992e5 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12235,6 +12235,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (34 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                     ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 37/40] c++, libstdc++: Implement __is_signed built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (35 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                     ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_signed.C         | 47 ++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C            | 12 ++---
 libstdc++-v3/include/bits/charconv.h         |  2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |  6 +--
 libstdc++-v3/include/bits/uniform_int_dist.h |  4 +-
 libstdc++-v3/include/ext/numeric_traits.h    | 18 ++++----
 10 files changed, 79 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 611e84cbbfd..f0b5fe9cb3b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b5c6b4992e5..58011a45cc6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 38/40] libstdc++: Optimize is_signed trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (36 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                     ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 39/40] c++, libstdc++: Implement __is_scalar built-in trait
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (37 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:21   ` [PATCH v12 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scalar.C        | 31 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 10 +++----
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +--
 libstdc++-v3/include/bits/cpp_type_traits.h |  2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |  8 +++---
 libstdc++-v3/include/bits/valarray_array.h  |  2 +-
 10 files changed, 55 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index f0b5fe9cb3b..4e220262020 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 58011a45cc6..1a6a04586fc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12413,6 +12416,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v12 40/40] libstdc++: Optimize is_scalar trait performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (38 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-09-15  2:21   ` Ken Matsui
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 00/40] Optimize type traits performance
  2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
                     ` (39 preceding siblings ...)
  2023-09-15  2:21   ` [PATCH v12 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-09-15  2:34   ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
                       ` (40 more replies)
  40 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v13:

	* Fixed ambiguous commit message and comment

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (40):
  c++: Sort built-in identifiers alphabetically
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c, c++: Use 16 bits for all use of enum rid for more keyword space
  c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.h                       |   2 +-
 gcc/c-family/c-indentation.h                  |   2 +-
 gcc/c/c-parser.cc                             |   6 +-
 gcc/c/c-parser.h                              |  14 +-
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/parser.h                               |   8 +-
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 ++++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libcpp/include/cpplib.h                       |   7 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 ++++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 42 files changed, 1356 insertions(+), 257 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 01/40] c++: Sort built-in identifiers alphabetically
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 02/40] c++: Implement __is_const built-in trait Ken Matsui
                       ` (39 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..ce3733df641 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..92f4f3fd4f6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12075,15 +12075,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12092,17 +12083,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12116,18 +12116,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12136,6 +12139,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12151,6 +12160,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12181,24 +12199,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12311,9 +12311,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12333,12 +12333,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12357,8 +12357,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12421,25 +12421,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 02/40] c++: Implement __is_const built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
                       ` (38 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ce3733df641..a4ebfd9f319 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 92f4f3fd4f6..17d6e6728f9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12356,6 +12359,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 03/40] libstdc++: Optimize is_const trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 02/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
                       ` (37 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 04/40] c++: Implement __is_volatile built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (2 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                       ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index a4ebfd9f319..60462cd9874 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 17d6e6728f9..647124265a6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12363,6 +12366,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 05/40] libstdc++: Optimize is_volatile trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (3 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 06/40] c++: Implement __is_array built-in trait Ken Matsui
                       ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 06/40] c++: Implement __is_array built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (4 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
                       ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 60462cd9874..c9106242bc8 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 647124265a6..8d5d443d9a9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12361,6 +12364,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 07/40] libstdc++: Optimize is_array trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (5 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 06/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                       ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 08/40] c++: Implement __is_unbounded_array built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (6 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                       ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c9106242bc8..1e67a3d2089 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5d443d9a9..fd7bdf7a293 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12369,6 +12372,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 09/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (7 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                       ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 10/40] c++: Implement __is_bounded_array built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (8 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                       ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1e67a3d2089..b6146c010f6 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index fd7bdf7a293..605cf03c18d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12368,6 +12371,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 11/40] libstdc++: Optimize is_bounded_array trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (9 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                       ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 12/40] c++: Implement __is_scoped_enum built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (10 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                       ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b6146c010f6..047307c95ce 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 605cf03c18d..c971c34cf6f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12190,6 +12190,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 13/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (11 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                       ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 14/40] c++: Implement __is_member_pointer built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (12 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                       ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 047307c95ce..7fed3483221 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c971c34cf6f..7091e581ac7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 15/40] libstdc++: Optimize is_member_pointer trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (13 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
                       ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (14 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
                       ` (24 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Now that RID_MAX has reached 255, we need to update the bit sizes of every
use of the enum rid from 8 to 16 to support more keywords.

For struct token_indent_info, the 8-bit increase does not change the overall
struct size because the 8-bit just consumes 1 byte from 2 bytes of external
fragmentation.  Since reordering the fields just changes 1 byte of internal
fragmentation to 1 byte of external fragmentation, I keep the original field
order.

For struct c_token, the 8-bit expansion increased the overall struct size from
24 bytes to 32 bytes.  The original struct takes 4 bytes of internal
fragmentation (after the location field) and 3 bytes of external
fragmentation.  Keeping the original order with the 8-bit expansion gives
7 bytes of internal fragmentation (3 bytes after the pragma_kind field + 4
bytes after the location field) and 7 bytes of external fragmentation. Since
the original field order was not optimal, reordering the fields results in the
same overall size as the original one.  I updated the field order to the most
efficient order.

For struct cp_token, reordering the fields only minimizes internal
fragmentation and does not minimize the overall struct size.  I keep the
original field order. The original struct size was 16 bytes with 3 bits of
internal fragmentation.  With this 8-bit update, the overall size would be
24 bytes.  Since there is no external fragmentation and 7 bytes + 3 bits of
internal fragmentation, reordering the fields does not minimize the overall
size.  I keep the orignal field order.

Suppose a pointer takes 8 bytes and int takes 4 bytes. Then, struct
ht_identifier takes 16 bytes, and union _cpp_hashnode_value takes 8 bytes.
For struct cpp_hashnode, the 8-bit increase consumes 1 more byte, resulting in
33 bytes except for paddings.  The original overall size before the 8-bit
increase was 32 bytes.  However, due to fragmentation, the overall struct size
would be 40 bytes.  Since there is no external fragmentation and 3 bytes + 5
bits of internal fragmentation, reordering the fields does not minimize the
overall size.  I keep the original field order.

gcc/c-family/ChangeLog:

	* c-indentation.h (struct token_indent_info): Make keyword 16 bits.

gcc/c/ChangeLog:

	* c-parser.cc (c_parse_init): Handle RID_MAX not to exceed the max
	value of 16 bits.
	* c-parser.h (struct c_token): Make keyword 16 bits. Reorder the
	fields to minimize memory fragmentation.

gcc/cp/ChangeLog:

	* parser.h (struct cp_token): Make keyword 16 bits.
	(struct cp_lexer): Make saved_keyword 16 bits.

libcpp/ChangeLog:

	* include/cpplib.h (struct cpp_hashnode): Make rid_code 16 bits.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-indentation.h |  2 +-
 gcc/c/c-parser.cc            |  6 +++---
 gcc/c/c-parser.h             | 14 +++++++-------
 gcc/cp/parser.h              |  8 +++++---
 libcpp/include/cpplib.h      |  7 +++++--
 5 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index c0e07bf49f1..6d2b88f01a3 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -26,7 +26,7 @@ struct token_indent_info
 {
   location_t location;
   ENUM_BITFIELD (cpp_ttype) type : 8;
-  ENUM_BITFIELD (rid) keyword : 8;
+  ENUM_BITFIELD (rid) keyword : 16;
 };
 
 /* Extract token information from TOKEN, which ought to either be a
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b9a1b75ca43..2086f253923 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -115,9 +115,9 @@ c_parse_init (void)
   tree id;
   int mask = 0;
 
-  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
-     the c_token structure.  */
-  gcc_assert (RID_MAX <= 255);
+  /* Make sure RID_MAX hasn't grown past the 16 bits used to hold the keyword
+     in the c_token structure.  */
+  gcc_assert (RID_MAX <= 65535);
 
   mask |= D_CXXONLY;
   if (!flag_isoc99)
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 545f0f4d9eb..6a9bd22a793 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -51,21 +51,21 @@ enum c_id_kind {
 /* A single C token after string literal concatenation and conversion
    of preprocessing tokens to tokens.  */
 struct GTY (()) c_token {
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* The location at which this token was found.  */
+  location_t location;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 16;
   /* The kind of token.  */
   ENUM_BITFIELD (cpp_ttype) type : 8;
   /* If this token is a CPP_NAME, this value indicates whether also
      declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
   ENUM_BITFIELD (c_id_kind) id_kind : 8;
-  /* If this token is a keyword, this value indicates which keyword.
-     Otherwise, this value is RID_MAX.  */
-  ENUM_BITFIELD (rid) keyword : 8;
   /* If this token is a CPP_PRAGMA, this indicates the pragma that
      was seen.  Otherwise it is PRAGMA_NONE.  */
   ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
-  /* The location at which this token was found.  */
-  location_t location;
-  /* The value associated with this token, if any.  */
-  tree value;
   /* Token flags.  */
   unsigned char flags;
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6cbb9a8e031..7aa251d11b1 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -44,7 +44,7 @@ struct GTY (()) cp_token {
   enum cpp_ttype type : 8;
   /* If this token is a keyword, this value indicates which keyword.
      Otherwise, this value is RID_MAX.  */
-  enum rid keyword : 8;
+  enum rid keyword : 16;
   /* Token flags.  */
   unsigned char flags;
   /* True if this token is from a context where it is implicitly extern "C" */
@@ -59,7 +59,9 @@ struct GTY (()) cp_token {
   bool purged_p : 1;
   bool tree_check_p : 1;
   bool main_source_p : 1;
-  /* 3 unused bits.  */
+  /* These booleans use 5 bits within 1 byte, resulting in 3 unused bits.
+     Since there would be 3 bytes of internal fragmentation to the location
+     field, the total unused bits would be 27 (= 3 + 24).  */
 
   /* The location at which this token was found.  */
   location_t location;
@@ -102,7 +104,7 @@ struct GTY (()) cp_lexer {
 
   /* Saved pieces of end token we replaced with the eof token.  */
   enum cpp_ttype saved_type : 8;
-  enum rid saved_keyword : 8;
+  enum rid saved_keyword : 16;
 
   /* The next lexer in a linked list of lexers.  */
   struct cp_lexer *next;
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index fcdaf082b09..7c37b861a77 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -988,11 +988,14 @@ struct GTY(()) cpp_hashnode {
   unsigned int directive_index : 7;	/* If is_directive,
 					   then index into directive table.
 					   Otherwise, a NODE_OPERATOR.  */
-  unsigned int rid_code : 8;		/* Rid code - for front ends.  */
+  unsigned int rid_code : 16;		/* Rid code - for front ends.  */
   unsigned int flags : 9;		/* CPP flags.  */
   ENUM_BITFIELD(node_type) type : 2;	/* CPP node type.  */
 
-  /* 5 bits spare.  */
+  /* These bitfields use 35 bits (= 1 + 7 + 16 + 9 + 2).  The exceeded 3 bits
+     in terms of bytes leave 5 unused bits within 1 byte.  Since there would
+     be 3 bytes of internal fragmentation to the deferred field, the total
+     unused bits would be 29 (= 5 + 24).  */
 
   /* The deferred cookie is applicable to NT_USER_MACRO or NT_VOID.
      The latter for when a macro had a prevailing undef.
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (15 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                       ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Andrew Pinski

This patch fixes incorrect handling for the new 16-bit rid code. Unsigned
char was previously used for the 8-bit rid code, but unsigned short is now
required.

gcc/c-family/ChangeLog:

	* c-common.h (C_SET_RID_CODE): Use unsigned short instead of
	unsigned char.

Ref: Initial discussion: https://gcc.gnu.org/pipermail/gcc/2023-September/242460.html
     Code provided by Andrew: https://gcc.gnu.org/pipermail/gcc/2023-September/242461.html
Co-authored-by: Andrew Pinski <pinskia@gmail.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..73bc23fa49f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -382,7 +382,7 @@ enum c_tree_index
 #define C_RID_CODE(id) \
   ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code))
 #define C_SET_RID_CODE(id, code) \
-  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code)
+  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned short) code)
 
 /* Identifier part common to the C front ends.  Inherits from
    tree_identifier, despite appearances.  */
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (16 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:34     ` [PATCH v13 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                       ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 7fed3483221..6ebe3984d17 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7091e581ac7..93e166923b8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12381,6 +12384,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (17 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-09-15  2:34     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                       ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (18 preceding siblings ...)
  2023-09-15  2:34     ` [PATCH v13 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                       ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6ebe3984d17..47649150ab5 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 93e166923b8..95b25c1348b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12172,6 +12172,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12385,6 +12388,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (19 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                       ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 22/40] c++: Implement __is_reference built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (20 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                       ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 47649150ab5..ac9fa026b4e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 95b25c1348b..bee27b25974 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 23/40] libstdc++: Optimize is_reference trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (21 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 24/40] c++: Implement __is_function built-in trait Ken Matsui
                       ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 24/40] c++: Implement __is_function built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (22 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                       ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ac9fa026b4e..3bb33a3d5c0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bee27b25974..a502c13ecc1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12163,6 +12163,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 25/40] libstdc++: Optimize is_function trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (23 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 26/40] libstdc++: Optimize is_object " Ken Matsui
                       ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 26/40] libstdc++: Optimize is_object trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (24 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                       ` (14 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 27/40] c++: Implement __remove_pointer built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (25 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                       ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 3bb33a3d5c0..07cd14b6e85 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a502c13ecc1..10656017bbc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12473,6 +12473,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (26 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                       ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 29/40] c++, libstdc++: Implement __is_pointer built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (27 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                       ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C       | 51 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 22 ++++-----
 gcc/testsuite/g++.dg/torture/20070621-1.C   |  4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  6 +--
 libstdc++-v3/include/bits/deque.tcc         |  6 +--
 libstdc++-v3/include/bits/stl_algobase.h    |  6 +--
 11 files changed, 86 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 07cd14b6e85..bc2bb5e5abb 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 10656017bbc..131ca8b96e6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12397,6 +12400,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 30/40] libstdc++: Optimize is_pointer trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (28 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                       ` (10 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (29 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                       ` (9 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_arithmetic.C    | 33 ++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  6 +--
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  4 +-
 libstdc++-v3/include/c_global/cmath         | 48 ++++++++++-----------
 libstdc++-v3/include/c_std/cmath            | 24 +++++------
 libstdc++-v3/include/tr1/cmath              | 24 +++++------
 11 files changed, 99 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index bc2bb5e5abb..06c203ce4de 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 131ca8b96e6..553a51dc16d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (30 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                       ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (31 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 34/40] libstdc++: Optimize is_compound " Ken Matsui
                       ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 34/40] libstdc++: Optimize is_compound trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (32 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                       ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 35/40] c++: Implement __is_unsigned built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (33 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                       ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unsigned.C   | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 06c203ce4de..611e84cbbfd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 553a51dc16d..b5c6b4992e5 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12235,6 +12235,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (34 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                       ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 37/40] c++, libstdc++: Implement __is_signed built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (35 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                       ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_signed.C         | 47 ++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C            | 12 ++---
 libstdc++-v3/include/bits/charconv.h         |  2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |  6 +--
 libstdc++-v3/include/bits/uniform_int_dist.h |  4 +-
 libstdc++-v3/include/ext/numeric_traits.h    | 18 ++++----
 10 files changed, 79 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 611e84cbbfd..f0b5fe9cb3b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b5c6b4992e5..58011a45cc6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 38/40] libstdc++: Optimize is_signed trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (36 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                       ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 39/40] c++, libstdc++: Implement __is_scalar built-in trait
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (37 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-09-15  2:35     ` [PATCH v13 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scalar.C        | 31 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 10 +++----
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +--
 libstdc++-v3/include/bits/cpp_type_traits.h |  2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |  8 +++---
 libstdc++-v3/include/bits/valarray_array.h  |  2 +-
 10 files changed, 55 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index f0b5fe9cb3b..4e220262020 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 58011a45cc6..1a6a04586fc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12413,6 +12416,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v13 40/40] libstdc++: Optimize is_scalar trait performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (38 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-09-15  2:35     ` Ken Matsui
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15  2:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-14 17:53   ` Joseph Myers
  2023-09-14 21:44     ` Ken Matsui
@ 2023-09-15 23:26     ` Ken Matsui
  1 sibling, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:26 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Ken Matsui, gcc-patches, libstdc++

On Thu, Sep 14, 2023 at 10:54 AM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Wed, 13 Sep 2023, Ken Matsui via Gcc-patches wrote:
>
> > diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
> > index 545f0f4d9eb..eed6deaf0f8 100644
> > --- a/gcc/c/c-parser.h
> > +++ b/gcc/c/c-parser.h
> > @@ -51,14 +51,14 @@ enum c_id_kind {
> >  /* A single C token after string literal concatenation and conversion
> >     of preprocessing tokens to tokens.  */
> >  struct GTY (()) c_token {
> > +  /* If this token is a keyword, this value indicates which keyword.
> > +     Otherwise, this value is RID_MAX.  */
> > +  ENUM_BITFIELD (rid) keyword : 16;
> >    /* The kind of token.  */
> >    ENUM_BITFIELD (cpp_ttype) type : 8;
> >    /* If this token is a CPP_NAME, this value indicates whether also
> >       declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
> >    ENUM_BITFIELD (c_id_kind) id_kind : 8;
> > -  /* If this token is a keyword, this value indicates which keyword.
> > -     Otherwise, this value is RID_MAX.  */
> > -  ENUM_BITFIELD (rid) keyword : 8;
> >    /* If this token is a CPP_PRAGMA, this indicates the pragma that
> >       was seen.  Otherwise it is PRAGMA_NONE.  */
> >    ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
>
> If you want to optimize layout, I'd expect flags to move so it can share
> the same 32-bit unit as the pragma_kind bit-field (not sure if any changes
> should be made to the declaration of flags to maximise the chance of such
> sharing across different host bit-field ABIs).
>
> > diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
> > index 6cbb9a8e031..3c3c482c6ce 100644
> > --- a/gcc/cp/parser.h
> > +++ b/gcc/cp/parser.h
> > @@ -40,11 +40,11 @@ struct GTY(()) tree_check {
> >  /* A C++ token.  */
> >
> >  struct GTY (()) cp_token {
> > -  /* The kind of token.  */
> > -  enum cpp_ttype type : 8;
> >    /* If this token is a keyword, this value indicates which keyword.
> >       Otherwise, this value is RID_MAX.  */
> > -  enum rid keyword : 8;
> > +  enum rid keyword : 16;
> > +  /* The kind of token.  */
> > +  enum cpp_ttype type : 8;
> >    /* Token flags.  */
> >    unsigned char flags;
> >    /* True if this token is from a context where it is implicitly extern "C" */
>
> You're missing an update to the "3 unused bits." comment further down.
>
> > @@ -988,7 +988,7 @@ struct GTY(()) cpp_hashnode {
> >    unsigned int directive_index : 7;  /* If is_directive,
> >                                          then index into directive table.
> >                                          Otherwise, a NODE_OPERATOR.  */
> > -  unsigned int rid_code : 8;         /* Rid code - for front ends.  */
> > +  unsigned int rid_code : 16;                /* Rid code - for front ends.  */
> >    unsigned int flags : 9;            /* CPP flags.  */
> >    ENUM_BITFIELD(node_type) type : 2; /* CPP node type.  */
>
> You're missing an update to the "5 bits spare." comment further down.
>
> Do you have any figures for the effects on compilation time or memory
> usage from the increase in size of these structures?
>

Here is the benchmark result:

https://github.com/ken-matsui/gsoc23/tree/main/reports/gcc-build

I can see regression for compilation time but not for memory.

* Time: +0.950995%
* Memory: No difference proven at 95.0% confidence

Sincerely,
Ken Matsui

> --
> Joseph S. Myers
> joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 00/40] Optimize type traits performance
  2023-09-15  2:34     ` [PATCH v13 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-15 23:50       ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
                           ` (39 more replies)
  0 siblings, 40 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v14:

	* Attached the benchmark results of the enum rid change

Changes in v13:

	* Fixed ambiguous commit message and comment

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (40):
  c++: Sort built-in identifiers alphabetically
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c, c++: Use 16 bits for all use of enum rid for more keyword space
  c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.h                       |   2 +-
 gcc/c-family/c-indentation.h                  |   2 +-
 gcc/c/c-parser.cc                             |   6 +-
 gcc/c/c-parser.h                              |  14 +-
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/parser.h                               |   8 +-
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 ++++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libcpp/include/cpplib.h                       |   7 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 ++++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 42 files changed, 1356 insertions(+), 257 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 01/40] c++: Sort built-in identifiers alphabetically
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 02/40] c++: Implement __is_const built-in trait Ken Matsui
                           ` (38 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..ce3733df641 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0f7f4e87ae4..92f4f3fd4f6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12075,15 +12075,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12092,17 +12083,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12116,18 +12116,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12136,6 +12139,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12151,6 +12160,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12181,24 +12199,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12311,9 +12311,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12333,12 +12333,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12357,8 +12357,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12421,25 +12421,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 02/40] c++: Implement __is_const built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
                           ` (37 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ce3733df641..a4ebfd9f319 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 92f4f3fd4f6..17d6e6728f9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12356,6 +12359,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 03/40] libstdc++: Optimize is_const trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 02/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
                           ` (36 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 04/40] c++: Implement __is_volatile built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (2 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                           ` (35 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index a4ebfd9f319..60462cd9874 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 17d6e6728f9..647124265a6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12363,6 +12366,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 05/40] libstdc++: Optimize is_volatile trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (3 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 06/40] c++: Implement __is_array built-in trait Ken Matsui
                           ` (34 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 06/40] c++: Implement __is_array built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (4 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
                           ` (33 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 60462cd9874..c9106242bc8 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 647124265a6..8d5d443d9a9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12361,6 +12364,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 07/40] libstdc++: Optimize is_array trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (5 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 06/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                           ` (32 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 08/40] c++: Implement __is_unbounded_array built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (6 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                           ` (31 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c9106242bc8..1e67a3d2089 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5d443d9a9..fd7bdf7a293 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12202,6 +12202,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12369,6 +12372,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 09/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (7 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                           ` (30 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 10/40] c++: Implement __is_bounded_array built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (8 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                           ` (29 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1e67a3d2089..b6146c010f6 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index fd7bdf7a293..605cf03c18d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12139,6 +12139,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12368,6 +12371,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 11/40] libstdc++: Optimize is_bounded_array trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (9 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                           ` (28 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 12/40] c++: Implement __is_scoped_enum built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (10 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:50         ` [PATCH v14 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                           ` (27 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b6146c010f6..047307c95ce 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 605cf03c18d..c971c34cf6f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12190,6 +12190,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 13/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (11 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-09-15 23:50         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                           ` (26 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:50 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 14/40] c++: Implement __is_member_pointer built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (12 preceding siblings ...)
  2023-09-15 23:50         ` [PATCH v14 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                           ` (25 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 047307c95ce..7fed3483221 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c971c34cf6f..7091e581ac7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 15/40] libstdc++: Optimize is_member_pointer trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (13 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
                           ` (24 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (14 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-19 16:58           ` Jason Merrill
  2023-09-15 23:51         ` [PATCH v14 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
                           ` (23 subsequent siblings)
  39 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Now that RID_MAX has reached 255, we need to update the bit sizes of every
use of the enum rid from 8 to 16 to support more keywords.

For struct token_indent_info, the 8-bit increase does not change the overall
struct size because the 8-bit just consumes 1 byte from 2 bytes of external
fragmentation.  Since reordering the fields just changes 1 byte of internal
fragmentation to 1 byte of external fragmentation, I keep the original field
order as-is.

For struct c_token, the 8-bit expansion increased the overall struct size from
24 bytes to 32 bytes.  The original struct takes 4 bytes of internal
fragmentation (after the location field) and 3 bytes of external
fragmentation.  Keeping the original order with the 8-bit expansion gives
7 bytes of internal fragmentation (3 bytes after the pragma_kind field + 4
bytes after the location field) and 7 bytes of external fragmentation. Since
the original field order was not optimal, reordering the fields results in the
same overall size as the original one.  I updated the field order to the most
efficient order.

For struct cp_token, reordering the fields only minimizes internal
fragmentation and does not minimize the overall struct size.  I keep the
original field order. The original struct size was 16 bytes with 3 bits of
internal fragmentation.  With this 8-bit update, the overall size would be
24 bytes.  Since there is no external fragmentation and 7 bytes + 3 bits of
internal fragmentation, reordering the fields does not minimize the overall
size.  I keep the orignal field order as-is.

Suppose a pointer takes 8 bytes and int takes 4 bytes. Then, struct
ht_identifier takes 16 bytes, and union _cpp_hashnode_value takes 8 bytes.
For struct cpp_hashnode, the 8-bit increase consumes 1 more byte, yielding
33 bytes except for paddings.  The original overall size before the 8-bit
increase was 32 bytes.  However, due to fragmentation, the overall struct size
would be 40 bytes.  Since there is no external fragmentation and 3 bytes + 5
bits of internal fragmentation, reordering the fields does not minimize the
overall size.  I keep the original field order as-is.

In total, at least 16 (= 8 + 8) bytes have increased.  This caused a
performance regression of +0.95% in compilation time, but no negative impact
on memory performance was observed.  This benchmark was taken by building GCC
10 times.  For more detailed information about the benchmark results, please
refer to the following link.

https://github.com/ken-matsui/gsoc23/blob/main/reports/gcc-build

gcc/c-family/ChangeLog:

	* c-indentation.h (struct token_indent_info): Make keyword 16 bits.

gcc/c/ChangeLog:

	* c-parser.cc (c_parse_init): Handle RID_MAX not to exceed the max
	value of 16 bits.
	* c-parser.h (struct c_token): Make keyword 16 bits. Reorder the
	fields to minimize memory fragmentation.

gcc/cp/ChangeLog:

	* parser.h (struct cp_token): Make keyword 16 bits.
	(struct cp_lexer): Make saved_keyword 16 bits.

libcpp/ChangeLog:

	* include/cpplib.h (struct cpp_hashnode): Make rid_code 16 bits.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-indentation.h |  2 +-
 gcc/c/c-parser.cc            |  6 +++---
 gcc/c/c-parser.h             | 14 +++++++-------
 gcc/cp/parser.h              |  8 +++++---
 libcpp/include/cpplib.h      |  7 +++++--
 5 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/gcc/c-family/c-indentation.h b/gcc/c-family/c-indentation.h
index c0e07bf49f1..6d2b88f01a3 100644
--- a/gcc/c-family/c-indentation.h
+++ b/gcc/c-family/c-indentation.h
@@ -26,7 +26,7 @@ struct token_indent_info
 {
   location_t location;
   ENUM_BITFIELD (cpp_ttype) type : 8;
-  ENUM_BITFIELD (rid) keyword : 8;
+  ENUM_BITFIELD (rid) keyword : 16;
 };
 
 /* Extract token information from TOKEN, which ought to either be a
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b9a1b75ca43..2086f253923 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -115,9 +115,9 @@ c_parse_init (void)
   tree id;
   int mask = 0;
 
-  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
-     the c_token structure.  */
-  gcc_assert (RID_MAX <= 255);
+  /* Make sure RID_MAX hasn't grown past the 16 bits used to hold the keyword
+     in the c_token structure.  */
+  gcc_assert (RID_MAX <= 65535);
 
   mask |= D_CXXONLY;
   if (!flag_isoc99)
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 545f0f4d9eb..6a9bd22a793 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -51,21 +51,21 @@ enum c_id_kind {
 /* A single C token after string literal concatenation and conversion
    of preprocessing tokens to tokens.  */
 struct GTY (()) c_token {
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* The location at which this token was found.  */
+  location_t location;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 16;
   /* The kind of token.  */
   ENUM_BITFIELD (cpp_ttype) type : 8;
   /* If this token is a CPP_NAME, this value indicates whether also
      declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
   ENUM_BITFIELD (c_id_kind) id_kind : 8;
-  /* If this token is a keyword, this value indicates which keyword.
-     Otherwise, this value is RID_MAX.  */
-  ENUM_BITFIELD (rid) keyword : 8;
   /* If this token is a CPP_PRAGMA, this indicates the pragma that
      was seen.  Otherwise it is PRAGMA_NONE.  */
   ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
-  /* The location at which this token was found.  */
-  location_t location;
-  /* The value associated with this token, if any.  */
-  tree value;
   /* Token flags.  */
   unsigned char flags;
 
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6cbb9a8e031..7aa251d11b1 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -44,7 +44,7 @@ struct GTY (()) cp_token {
   enum cpp_ttype type : 8;
   /* If this token is a keyword, this value indicates which keyword.
      Otherwise, this value is RID_MAX.  */
-  enum rid keyword : 8;
+  enum rid keyword : 16;
   /* Token flags.  */
   unsigned char flags;
   /* True if this token is from a context where it is implicitly extern "C" */
@@ -59,7 +59,9 @@ struct GTY (()) cp_token {
   bool purged_p : 1;
   bool tree_check_p : 1;
   bool main_source_p : 1;
-  /* 3 unused bits.  */
+  /* These booleans use 5 bits within 1 byte, resulting in 3 unused bits.
+     Since there would be 3 bytes of internal fragmentation to the location
+     field, the total unused bits would be 27 (= 3 + 24).  */
 
   /* The location at which this token was found.  */
   location_t location;
@@ -102,7 +104,7 @@ struct GTY (()) cp_lexer {
 
   /* Saved pieces of end token we replaced with the eof token.  */
   enum cpp_ttype saved_type : 8;
-  enum rid saved_keyword : 8;
+  enum rid saved_keyword : 16;
 
   /* The next lexer in a linked list of lexers.  */
   struct cp_lexer *next;
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index fcdaf082b09..7c37b861a77 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -988,11 +988,14 @@ struct GTY(()) cpp_hashnode {
   unsigned int directive_index : 7;	/* If is_directive,
 					   then index into directive table.
 					   Otherwise, a NODE_OPERATOR.  */
-  unsigned int rid_code : 8;		/* Rid code - for front ends.  */
+  unsigned int rid_code : 16;		/* Rid code - for front ends.  */
   unsigned int flags : 9;		/* CPP flags.  */
   ENUM_BITFIELD(node_type) type : 2;	/* CPP node type.  */
 
-  /* 5 bits spare.  */
+  /* These bitfields use 35 bits (= 1 + 7 + 16 + 9 + 2).  The exceeded 3 bits
+     in terms of bytes leave 5 unused bits within 1 byte.  Since there would
+     be 3 bytes of internal fragmentation to the deferred field, the total
+     unused bits would be 29 (= 5 + 24).  */
 
   /* The deferred cookie is applicable to NT_USER_MACRO or NT_VOID.
      The latter for when a macro had a prevailing undef.
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (15 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                           ` (22 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Andrew Pinski

This patch fixes incorrect handling for the new 16-bit rid code. Unsigned
char was previously used for the 8-bit rid code, but unsigned short is now
required.

gcc/c-family/ChangeLog:

	* c-common.h (C_SET_RID_CODE): Use unsigned short instead of
	unsigned char.

Ref: Initial discussion: https://gcc.gnu.org/pipermail/gcc/2023-September/242460.html
     Code provided by Andrew: https://gcc.gnu.org/pipermail/gcc/2023-September/242461.html
Co-authored-by: Andrew Pinski <pinskia@gmail.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..73bc23fa49f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -382,7 +382,7 @@ enum c_tree_index
 #define C_RID_CODE(id) \
   ((enum rid) (((struct c_common_identifier *) (id))->node.rid_code))
 #define C_SET_RID_CODE(id, code) \
-  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned char) code)
+  (((struct c_common_identifier *) (id))->node.rid_code = (unsigned short) code)
 
 /* Identifier part common to the C front ends.  Inherits from
    tree_identifier, despite appearances.  */
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (16 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                           ` (21 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 7fed3483221..6ebe3984d17 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7091e581ac7..93e166923b8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12169,6 +12169,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12381,6 +12384,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (17 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                           ` (20 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (18 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                           ` (19 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6ebe3984d17..47649150ab5 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 93e166923b8..95b25c1348b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12172,6 +12172,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12385,6 +12388,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (19 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                           ` (18 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 22/40] c++: Implement __is_reference built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (20 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                           ` (17 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 47649150ab5..ac9fa026b4e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 95b25c1348b..bee27b25974 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 23/40] libstdc++: Optimize is_reference trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (21 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 24/40] c++: Implement __is_function built-in trait Ken Matsui
                           ` (16 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 24/40] c++: Implement __is_function built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (22 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                           ` (15 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index ac9fa026b4e..3bb33a3d5c0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bee27b25974..a502c13ecc1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12163,6 +12163,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12393,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 25/40] libstdc++: Optimize is_function trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (23 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 26/40] libstdc++: Optimize is_object " Ken Matsui
                           ` (14 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 26/40] libstdc++: Optimize is_object trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (24 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                           ` (13 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 27/40] c++: Implement __remove_pointer built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (25 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                           ` (12 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 3bb33a3d5c0..07cd14b6e85 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a502c13ecc1..10656017bbc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12473,6 +12473,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (26 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                           ` (11 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 29/40] c++, libstdc++: Implement __is_pointer built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (27 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                           ` (10 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C       | 51 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 22 ++++-----
 gcc/testsuite/g++.dg/torture/20070621-1.C   |  4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  6 +--
 libstdc++-v3/include/bits/deque.tcc         |  6 +--
 libstdc++-v3/include/bits/stl_algobase.h    |  6 +--
 11 files changed, 86 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 07cd14b6e85..bc2bb5e5abb 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 10656017bbc..131ca8b96e6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12196,6 +12196,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12397,6 +12400,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 30/40] libstdc++: Optimize is_pointer trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (28 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                           ` (9 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (29 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                           ` (8 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_arithmetic.C    | 33 ++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  6 +--
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |  4 +-
 libstdc++-v3/include/c_global/cmath         | 48 ++++++++++-----------
 libstdc++-v3/include/c_std/cmath            | 24 +++++------
 libstdc++-v3/include/tr1/cmath              | 24 +++++------
 11 files changed, 99 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index bc2bb5e5abb..06c203ce4de 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 131ca8b96e6..553a51dc16d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12128,6 +12128,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (30 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                           ` (7 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (31 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 34/40] libstdc++: Optimize is_compound " Ken Matsui
                           ` (6 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 34/40] libstdc++: Optimize is_compound trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (32 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                           ` (5 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 35/40] c++: Implement __is_unsigned built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (33 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                           ` (4 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unsigned.C   | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 06c203ce4de..611e84cbbfd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 553a51dc16d..b5c6b4992e5 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12235,6 +12235,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (34 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                           ` (3 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 37/40] c++, libstdc++: Implement __is_signed built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (35 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                           ` (2 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_signed.C         | 47 ++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C            | 12 ++---
 libstdc++-v3/include/bits/charconv.h         |  2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |  6 +--
 libstdc++-v3/include/bits/uniform_int_dist.h |  4 +-
 libstdc++-v3/include/ext/numeric_traits.h    | 18 ++++----
 10 files changed, 79 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 611e84cbbfd..f0b5fe9cb3b 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b5c6b4992e5..58011a45cc6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12410,6 +12413,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 38/40] libstdc++: Optimize is_signed trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (36 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 39/40] c++, libstdc++: Implement __is_scalar built-in trait
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (37 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  2023-09-15 23:51         ` [PATCH v14 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scalar.C        | 31 +++++++++++++++++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           | 10 +++----
 gcc/testsuite/g++.dg/torture/pr57107.C      |  4 +--
 libstdc++-v3/include/bits/cpp_type_traits.h |  2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |  8 +++---
 libstdc++-v3/include/bits/valarray_array.h  |  2 +-
 10 files changed, 55 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index f0b5fe9cb3b..4e220262020 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 58011a45cc6..1a6a04586fc 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12413,6 +12416,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v14 40/40] libstdc++: Optimize is_scalar trait performance
  2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
                           ` (38 preceding siblings ...)
  2023-09-15 23:51         ` [PATCH v14 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-09-15 23:51         ` Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-09-15 23:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-15 23:51         ` [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
@ 2023-09-19 16:58           ` Jason Merrill
  2023-09-19 23:05             ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Jason Merrill @ 2023-09-19 16:58 UTC (permalink / raw)
  To: Ken Matsui, gcc-patches; +Cc: libstdc++, Patrick Palka, Joseph S. Myers

On 9/15/23 19:51, Ken Matsui via Gcc-patches wrote:
> Now that RID_MAX has reached 255, we need to update the bit sizes of every
> use of the enum rid from 8 to 16 to support more keywords.

Sorry to bring this up so late, but this does raise the question of 
whether we actually want to use keyword space for all these traits that 
will probably be used approximately once in a C++ translation unit.  I 
wonder if it would make sense to instead use e.g. RID_TRAIT for all of 
them and use gperf to look up the specific trait from the identifier?

Jason


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-19 16:58           ` Jason Merrill
@ 2023-09-19 23:05             ` Ken Matsui
  2023-09-27 13:57               ` Jason Merrill
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-09-19 23:05 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Ken Matsui, gcc-patches, libstdc++, Patrick Palka, Joseph S. Myers

On Tue, Sep 19, 2023 at 9:59 AM Jason Merrill <jason@redhat.com> wrote:
>
> On 9/15/23 19:51, Ken Matsui via Gcc-patches wrote:
> > Now that RID_MAX has reached 255, we need to update the bit sizes of every
> > use of the enum rid from 8 to 16 to support more keywords.
>
> Sorry to bring this up so late, but this does raise the question of
> whether we actually want to use keyword space for all these traits that
> will probably be used approximately once in a C++ translation unit.  I
> wonder if it would make sense to instead use e.g. RID_TRAIT for all of
> them and use gperf to look up the specific trait from the identifier?
>

Thank you for your review. To use gperf, we might need to duplicate
the list of all traits defined in cp-trait.def. Modifying the traits
would require us to edit two files, but would it be acceptable?

> Jason
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-19 23:05             ` Ken Matsui
@ 2023-09-27 13:57               ` Jason Merrill
  2023-10-09  5:03                 ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Jason Merrill @ 2023-09-27 13:57 UTC (permalink / raw)
  To: Ken Matsui
  Cc: Ken Matsui, gcc-patches, libstdc++, Patrick Palka, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 1069 bytes --]

On Tue, Sep 19, 2023 at 7:05 PM Ken Matsui <kmatsui@cs.washington.edu>
wrote:

> On Tue, Sep 19, 2023 at 9:59 AM Jason Merrill <jason@redhat.com> wrote:
> >
> > On 9/15/23 19:51, Ken Matsui via Gcc-patches wrote:
> > > Now that RID_MAX has reached 255, we need to update the bit sizes of
> every
> > > use of the enum rid from 8 to 16 to support more keywords.
> >
> > Sorry to bring this up so late, but this does raise the question of
> > whether we actually want to use keyword space for all these traits that
> > will probably be used approximately once in a C++ translation unit.  I
> > wonder if it would make sense to instead use e.g. RID_TRAIT for all of
> > them and use gperf to look up the specific trait from the identifier?
> >
>
> Thank you for your review. To use gperf, we might need to duplicate
> the list of all traits defined in cp-trait.def. Modifying the traits
> would require us to edit two files, but would it be acceptable?
>

I think the gperf input could be generated from the .def with a simple
script?

Jason

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space
  2023-09-27 13:57               ` Jason Merrill
@ 2023-10-09  5:03                 ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-09  5:03 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Ken Matsui, gcc-patches, libstdc++, Patrick Palka, Joseph S. Myers

On Wed, Sep 27, 2023 at 6:57 AM Jason Merrill <jason@redhat.com> wrote:
>
> On Tue, Sep 19, 2023 at 7:05 PM Ken Matsui <kmatsui@cs.washington.edu> wrote:
>>
>> On Tue, Sep 19, 2023 at 9:59 AM Jason Merrill <jason@redhat.com> wrote:
>> >
>> > On 9/15/23 19:51, Ken Matsui via Gcc-patches wrote:
>> > > Now that RID_MAX has reached 255, we need to update the bit sizes of every
>> > > use of the enum rid from 8 to 16 to support more keywords.
>> >
>> > Sorry to bring this up so late, but this does raise the question of
>> > whether we actually want to use keyword space for all these traits that
>> > will probably be used approximately once in a C++ translation unit.  I
>> > wonder if it would make sense to instead use e.g. RID_TRAIT for all of
>> > them and use gperf to look up the specific trait from the identifier?
>> >
>>
>> Thank you for your review. To use gperf, we might need to duplicate
>> the list of all traits defined in cp-trait.def. Modifying the traits
>> would require us to edit two files, but would it be acceptable?
>
>
> I think the gperf input could be generated from the .def with a simple script?
>

Thank you! Will do!

> Jason

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 00/39] Optimize type traits performance
  2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
                       ` (39 preceding siblings ...)
  2023-09-15  2:35     ` [PATCH v13 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-10  9:46     ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
                         ` (39 more replies)
  40 siblings, 40 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v15:

	* Rebased on top of trunk
	* Use gperf to look up traits instead of enum rid

Changes in v14:

	* Added padding calculation to the commit message

Changes in v13:

	* Fixed ambiguous commit message and comment

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (39):
  c++: Sort built-in identifiers alphabetically
  c-family, c++: Look up traits through gperf instead of enum rid.
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc                      |  12 +-
 gcc/c-family/c-common.h                       |   7 +-
 gcc/cp/Make-lang.in                           |  26 ++
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-objcp-common.cc                     |   6 +-
 gcc/cp/cp-trait-head.in                       |  31 ++
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/cp-trait.gperf                         |  92 ++++++
 gcc/cp/cp-trait.h                             | 287 ++++++++++++++++++
 gcc/cp/parser.cc                              |  72 ++---
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 +++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 +++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 44 files changed, 1807 insertions(+), 300 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 01/39] c++: Sort built-in identifiers alphabetically
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 02/39] c-family, c++: Look up traits through gperf instead of enum rid Ken Matsui
                         ` (38 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 02/39] c-family, c++: Look up traits through gperf instead of enum rid.
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 03/39] c++: Implement __is_const built-in trait Ken Matsui
                         ` (37 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Since RID_MAX soon reaches 255 and all traits are used approximately once in
a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
	and RID_TRAIT_TYPE instead.
	* c-common.h (enum rid): Remove all existing RID values for traits.
	Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.

gcc/cp/ChangeLog:

	* Make-lang.in: Add targets to generate cp-trait.gperf and
	cp-trait.h.
	* cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
	for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
	type-yielding traits.  Use RID_TRAIT_TYPE instead.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Likewise, for expression-yielding
	traits.  Use RID_TRAIT_EXPR instead.
	(cp_parser_trait): Look up traits through gperf instead of enum rid.
	* cp-trait-head.in: New file.
	* cp-trait.gperf: New file.
	* cp-trait.h: New file.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |  12 +-
 gcc/c-family/c-common.h   |   7 +-
 gcc/cp/Make-lang.in       |  26 ++++
 gcc/cp/cp-objcp-common.cc |   6 +-
 gcc/cp/cp-trait-head.in   |  31 +++++
 gcc/cp/cp-trait.gperf     |  75 ++++++++++++
 gcc/cp/cp-trait.h         | 249 ++++++++++++++++++++++++++++++++++++++
 gcc/cp/parser.cc          |  72 ++++-------
 8 files changed, 418 insertions(+), 60 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..f219ccd29e5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
+#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_EXPR,	D_CXXONLY },
 #include "cp/cp-trait.def"
-#undef DEFTRAIT
+#undef DEFTRAIT_EXPR
   /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
+  { "__is_same_as",	RID_TRAIT_EXPR,	D_CXXONLY },
+#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_TYPE,	D_CXXONLY },
+#include "cp/cp-trait.def"
+#undef DEFTRAIT_TYPE
 
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..a1a641f4175 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,10 +168,9 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
+  /* C++ traits, defined in cp-trait.def.  */
+  RID_TRAIT_EXPR,
+  RID_TRAIT_TYPE,
 
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2727fb7f8cc..d27a6744cb9 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -34,6 +34,8 @@
 # - the compiler proper (eg: cc1plus)
 # - define the names for selecting the language in LANGUAGES.
 
+AWK = @AWK@
+
 # Actual names to use when installing a native compiler.
 CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
 GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,30 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+# We always need the dependency on the .gperf file because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+	gperf -o -C -E -D -N 'find' -L C++ \
+		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from a cp-trait.def file.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait.def
+	cat $(srcdir)/cp/cp-trait-head.in > $@
+	$(AWK) -F', *' '/^DEFTRAIT_/ { \
+		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+		gsub(/\)/, "", $$3); \
+		binary = ($$3 == 2 ? "true" : "false"); \
+		variadic = ($$3 == -1 ? "true" : "false"); \
+		print $$2", CPTK_" $$1", "binary", "variadic", "type; \
+	}' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..c414d8f5a13 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -434,10 +434,8 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
+    case RID_TRAIT_EXPR:
+    case RID_TRAIT_TYPE:
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
new file mode 100644
index 00000000000..efd2393e7a0
--- /dev/null
+++ b/gcc/cp/cp-trait-head.in
@@ -0,0 +1,31 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  bool binary;
+  bool variadic;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, true, false, false
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
new file mode 100644
index 00000000000..c3feb78d3c4
--- /dev/null
+++ b/gcc/cp/cp-trait.gperf
@@ -0,0 +1,75 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  bool binary;
+  bool variadic;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, true, false, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false
+"__is_abstract", CPTK_IS_ABSTRACT, false, false, false
+"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false
+"__is_base_of", CPTK_IS_BASE_OF, true, false, false
+"__is_class", CPTK_IS_CLASS, false, false, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false
+"__is_empty", CPTK_IS_EMPTY, false, false, false
+"__is_enum", CPTK_IS_ENUM, false, false, false
+"__is_final", CPTK_IS_FINAL, false, false, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false
+"__is_pod", CPTK_IS_POD, false, false, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
+"__is_same", CPTK_IS_SAME, true, false, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false
+"__is_trivial", CPTK_IS_TRIVIAL, false, false, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false
+"__is_union", CPTK_IS_UNION, false, false, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false
+"__remove_cv", CPTK_REMOVE_CV, false, false, true
+"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false
+"__bases", CPTK_BASES, false, false, true
+"__direct_bases", CPTK_DIRECT_BASES, false, false, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
new file mode 100644
index 00000000000..db9476a8ac1
--- /dev/null
+++ b/gcc/cp/cp-trait.h
@@ -0,0 +1,249 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+/* Computed positions: -k'8' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  bool binary;
+  bool variadic;
+  bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned char asso_values[] =
+    {
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
+       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
+      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
+      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        break;
+    }
+  return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 45,
+      MIN_WORD_LENGTH = 7,
+      MAX_WORD_LENGTH = 37,
+      MIN_HASH_VALUE = 7,
+      MAX_HASH_VALUE = 85
+    };
+
+  static const struct cp_trait wordlist[] =
+    {
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__bases", CPTK_BASES, false, false, true},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, false, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, false, false, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, false, false, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false}
+    };
+
+  static const signed char lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
+       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..555a0bf90bb 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "contracts.h"
 #include "bitmap.h"
 #include "builtins.h"
+#include "cp-trait.h"
 
 \f
 /* The lexer.  */
@@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* C++20 extensions.  */
     case RID_CONSTINIT:
     case RID_CONSTEVAL:
-      return true;
-
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
+      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
+    case RID_TRAIT_TYPE:
       return true;
 
     default:
@@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, tree);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
+	case RID_TRAIT_EXPR:
+	  return cp_parser_trait (parser, token->u.value);
 
 	// C++ concepts
 	case RID_REQUIRES:
@@ -11033,28 +11027,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, tree keyword)
 {
-  cp_trait_kind kind;
-  tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
+  const char* keyword_str = IDENTIFIER_POINTER (keyword);
+  int keyword_len = IDENTIFIER_LENGTH (keyword);
+  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
 
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  tree type1, type2 = NULL_TREE;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11042,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11058,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11073,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11110,7 +11089,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 	}
       type2 = trailing;
     }
-  else if (binary)
+  else if (trait->binary)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
 
@@ -11122,7 +11101,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
       if (type2 == error_mark_node)
 	return error_mark_node;
     }
-  else if (variadic)
+  else if (trait->variadic)
     {
       auto_vec<tree, 4> trailing;
       while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
@@ -11144,7 +11123,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11137,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,11 +20060,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    case RID_TRAIT_TYPE:
+      type = cp_parser_trait (parser, token->u.value);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 03/39] c++: Implement __is_const built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 02/39] c-family, c++: Look up traits through gperf instead of enum rid Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
                         ` (36 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_const.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 202 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_const.C      |  19 +++
 7 files changed, 134 insertions(+), 99 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index c3feb78d3c4..ad720832ccb 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -43,6 +43,7 @@ struct cp_trait {
 "__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false
 "__is_base_of", CPTK_IS_BASE_OF, true, false, false
 "__is_class", CPTK_IS_CLASS, false, false, false
+"__is_const", CPTK_IS_CONST, false, false, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false
 "__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false
 "__is_empty", CPTK_IS_EMPTY, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index db9476a8ac1..4a2100779cf 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -1,6 +1,6 @@
 /* C++ code produced by gperf version 3.1 */
 /* Command-line: gperf -o -C -E -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
-/* Computed positions: -k'8' */
+/* Computed positions: -k'6,8' */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 79, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
-       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
-      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
-      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
+      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
+      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -106,6 +106,8 @@ cp_trait_lookup::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
       case 7:
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
         break;
     }
   return hval;
@@ -116,116 +118,118 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 85
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
 #line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, true, false, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false}
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
-       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
-      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
-      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
-      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
+      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
+      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
+      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
+      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 04/39] libstdc++: Optimize is_const trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (2 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 03/39] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
                         ` (35 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 05/39] c++: Implement __is_volatile built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (3 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
                         ` (34 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_volatile.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 ++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/cp-trait.gperf                    |  1 +
 gcc/cp/cp-trait.h                        | 38 +++++++++++++-----------
 gcc/cp/semantics.cc                      |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C   | 19 ++++++++++++
 7 files changed, 51 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ad720832ccb..ead136495fd 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -64,6 +64,7 @@ struct cp_trait {
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false
 "__is_union", CPTK_IS_UNION, false, false, false
+"__is_volatile", CPTK_IS_VOLATILE, false, false, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false
 "__remove_cv", CPTK_REMOVE_CV, false, false, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 4a2100779cf..0fa702f1441 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -82,7 +82,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
       40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
       96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,27 +127,29 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
@@ -161,9 +163,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
@@ -217,19 +219,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
-      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
-      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
-      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
-      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
+      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
+      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 06/39] libstdc++: Optimize is_volatile trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (4 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 07/39] c++: Implement __is_array built-in trait Ken Matsui
                         ` (33 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 07/39] c++: Implement __is_array built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (5 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
                         ` (32 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 148 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_array.C      |  28 +++++
 7 files changed, 116 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ead136495fd..a0c313af253 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -40,6 +40,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false
 "__is_abstract", CPTK_IS_ABSTRACT, false, false, false
 "__is_aggregate", CPTK_IS_AGGREGATE, false, false, false
+"__is_array", CPTK_IS_ARRAY, false, false, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false
 "__is_base_of", CPTK_IS_BASE_OF, true, false, false
 "__is_class", CPTK_IS_CLASS, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 0fa702f1441..5796810aa81 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
-      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
-      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
+       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
+       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -118,108 +118,110 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 47,
+      TOTAL_KEYWORDS = 48,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, false, false, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
@@ -228,10 +230,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
       14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
-      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 47
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 08/39] libstdc++: Optimize is_array trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (6 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 07/39] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                         ` (31 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 09/39] c++: Implement __is_unbounded_array built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (7 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                         ` (30 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unbounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNBOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 42 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 ++++++++++++++++
 7 files changed, 71 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index a0c313af253..8059e1e8d9e 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -64,6 +64,7 @@ struct cp_trait {
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false
+"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false
 "__is_union", CPTK_IS_UNION, false, false, false
 "__is_volatile", CPTK_IS_VOLATILE, false, false, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 5796810aa81..b52f2985a66 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 48,
+      TOTAL_KEYWORDS = 49,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,30 +127,32 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
@@ -163,9 +165,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
@@ -221,21 +223,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
-      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
+      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
+      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 47
+      -1, -1, -1, 48
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 10/39] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (8 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
                         ` (29 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 11/39] c++: Implement __is_bounded_array built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (9 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                         ` (28 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_bounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_BOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |  3 +
 gcc/cp/cp-trait.def                         |  1 +
 gcc/cp/cp-trait.gperf                       |  1 +
 gcc/cp/cp-trait.h                           | 86 +++++++++++----------
 gcc/cp/semantics.cc                         |  4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  3 +
 gcc/testsuite/g++.dg/ext/is_bounded_array.C | 38 +++++++++
 7 files changed, 94 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 8059e1e8d9e..86d7453c9f8 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -43,6 +43,7 @@ struct cp_trait {
 "__is_array", CPTK_IS_ARRAY, false, false, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false
 "__is_base_of", CPTK_IS_BASE_OF, true, false, false
+"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false
 "__is_class", CPTK_IS_CLASS, false, false, false
 "__is_const", CPTK_IS_CONST, false, false, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b52f2985a66..a44498b4b90 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -82,7 +82,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
        50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
       116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 49,
+      TOTAL_KEYWORDS = 50,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,54 +127,56 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
@@ -183,7 +185,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
@@ -193,27 +195,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, false, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
@@ -221,9 +223,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
@@ -232,12 +234,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
-      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
+      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
+      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 48
+      -1, -1, -1, 49
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 12/39] libstdc++: Optimize is_bounded_array trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (10 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                         ` (27 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 13/39] c++: Implement __is_scoped_enum built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (11 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                         ` (26 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scoped_enum.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCOPED_ENUM.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                      |   3 +
 gcc/cp/cp-trait.def                       |   1 +
 gcc/cp/cp-trait.gperf                     |   1 +
 gcc/cp/cp-trait.h                         | 161 +++++++++++-----------
 gcc/cp/semantics.cc                       |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |   3 +
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C |  67 +++++++++
 7 files changed, 160 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 86d7453c9f8..705bf377b87 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -60,6 +60,7 @@ struct cp_trait {
 "__is_pod", CPTK_IS_POD, false, false, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
 "__is_same", CPTK_IS_SAME, true, false, false
+"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false
 "__is_trivial", CPTK_IS_TRIVIAL, false, false, false
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index a44498b4b90..8c5f0985f00 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
-       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
-      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
+      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
+      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
+      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -118,56 +118,60 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 50,
+      TOTAL_KEYWORDS = 51,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
@@ -175,22 +179,18 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
@@ -199,47 +199,48 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
-      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 49
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
+      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
+      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
+      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
+      50
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 14/39] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (12 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
                         ` (25 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 15/39] c++: Implement __is_member_pointer built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (13 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                         ` (24 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_MEMBER_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 153 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_member_pointer.C |  30 ++++
 7 files changed, 120 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 705bf377b87..d3f1343448b 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, false, false, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false
+"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 8c5f0985f00..3de93349f77 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 111, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
-      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
-      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
-      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
+       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
+       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
+      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118
     };
   unsigned int hval = len;
 
@@ -118,69 +118,67 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 51,
+      TOTAL_KEYWORDS = 52,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 117
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
@@ -189,58 +187,63 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false}
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
-      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
-      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
-      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
-      50
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
+      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
+      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
+      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
+      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
+      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, 51
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 16/39] libstdc++: Optimize is_member_pointer trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (14 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                         ` (23 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 17/39] c++: Implement __is_member_function_pointer built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (15 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                         ` (22 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_function_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_FUNCTION_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |   3 +
 gcc/cp/cp-trait.def                           |   1 +
 gcc/cp/cp-trait.gperf                         |   1 +
 gcc/cp/cp-trait.h                             | 176 +++++++++---------
 gcc/cp/semantics.cc                           |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |   3 +
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 7 files changed, 131 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index d3f1343448b..505f49bca07 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, false, false, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false
+"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 3de93349f77..0dcb08cc601 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 111, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
-       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
-       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
-      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
+      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
+      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
+      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -118,132 +118,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 52,
+      TOTAL_KEYWORDS = 53,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 117
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false}
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, false, false, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
-      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
-      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
-      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
-      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
-      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, 51
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
+      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 18/39] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (16 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                         ` (21 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 19/39] c++: Implement __is_member_object_pointer built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (17 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                         ` (20 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_object_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_OBJECT_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 +
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 62 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 +
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++
 7 files changed, 74 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 505f49bca07..4a099120512 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -54,6 +54,7 @@ struct cp_trait {
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false
+"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 0dcb08cc601..f1fce9914b0 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 53,
+      TOTAL_KEYWORDS = 54,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,57 +127,57 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
@@ -187,25 +187,25 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
@@ -213,12 +213,14 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
@@ -231,7 +233,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
@@ -242,8 +244,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
       -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
-      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
+      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 20/39] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (18 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 21/39] c++: Implement __is_reference built-in trait Ken Matsui
                         ` (19 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 21/39] c++: Implement __is_reference built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (19 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
                         ` (18 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_reference.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 113 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_reference.C  |  34 +++++++
 7 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 4a099120512..1d902612f5a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -62,6 +62,7 @@ struct cp_trait {
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false
 "__is_pod", CPTK_IS_POD, false, false, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
+"__is_reference", CPTK_IS_REFERENCE, false, false, false
 "__is_same", CPTK_IS_SAME, true, false, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f1fce9914b0..7aa695210ce 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 94, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
-      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
-      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
-      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
+       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
+       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
+      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   unsigned int hval = len;
 
@@ -118,58 +118,58 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 54,
+      TOTAL_KEYWORDS = 55,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 100
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
@@ -177,7 +177,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
@@ -187,7 +187,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
@@ -209,15 +209,13 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
@@ -225,6 +223,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
@@ -233,8 +233,10 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false}
     };
 
   static const signed char lookup[] =
@@ -243,9 +245,10 @@ cp_trait_lookup::find (const char *str, size_t len)
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
+      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      -1, -1, 54
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 22/39] libstdc++: Optimize is_reference trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (20 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 21/39] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 23/39] c++: Implement __is_function built-in trait Ken Matsui
                         ` (17 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 23/39] c++: Implement __is_function built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (21 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
                         ` (16 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_function.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 143 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_function.C   |  58 +++++++++
 7 files changed, 143 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 1d902612f5a..4fa14de3e90 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -51,6 +51,7 @@ struct cp_trait {
 "__is_empty", CPTK_IS_EMPTY, false, false, false
 "__is_enum", CPTK_IS_ENUM, false, false, false
 "__is_final", CPTK_IS_FINAL, false, false, false
+"__is_function", CPTK_IS_FUNCTION, false, false, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 7aa695210ce..c53e234f631 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 94, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
-       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
-       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
-      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
+       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
+       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
+      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -118,113 +118,113 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 55,
+      TOTAL_KEYWORDS = 56,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 100
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
@@ -233,10 +233,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false}
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
+#line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
@@ -244,11 +246,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
-      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      -1, -1, 54
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
+      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 55
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 24/39] libstdc++: Optimize is_function trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (22 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 23/39] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 25/39] libstdc++: Optimize is_object " Ken Matsui
                         ` (15 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 25/39] libstdc++: Optimize is_object trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (23 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
                         ` (14 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 26/39] c++: Implement __remove_pointer built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (24 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 25/39] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                         ` (13 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/cp-trait.gperf                     |  1 +
 gcc/cp/cp-trait.h                         | 32 +++++++-------
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 6 files changed, 78 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 4fa14de3e90..de3779b6d82 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -78,6 +78,7 @@ struct cp_trait {
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false
 "__remove_cv", CPTK_REMOVE_CV, false, false, true
 "__remove_cvref", CPTK_REMOVE_CVREF, false, false, true
+"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true
 "__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true
 "__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true
 "__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index c53e234f631..503e6804145 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 56,
+      TOTAL_KEYWORDS = 57,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,7 +127,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
@@ -139,17 +139,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
@@ -237,21 +239,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, false, false, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
-      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 55
+       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
+      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
+      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
+      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 56
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 27/39] libstdc++: Optimize remove_pointer trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (25 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                         ` (12 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 28/39] c++, libstdc++: Implement __is_pointer built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (26 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
                         ` (11 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 155 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_pointer.C       |  51 +++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  22 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C   |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   6 +-
 libstdc++-v3/include/bits/deque.tcc         |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   6 +-
 13 files changed, 165 insertions(+), 101 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index de3779b6d82..07a333ea826 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -62,6 +62,7 @@ struct cp_trait {
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false
 "__is_pod", CPTK_IS_POD, false, false, false
+"__is_pointer", CPTK_IS_POINTER, false, false, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
 "__is_reference", CPTK_IS_REFERENCE, false, false, false
 "__is_same", CPTK_IS_SAME, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 503e6804145..011e454760c 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
-       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
-       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
-      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
+       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
+      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
+      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -118,78 +118,78 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 57,
+      TOTAL_KEYWORDS = 58,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, false, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 86 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
@@ -207,23 +207,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
@@ -238,22 +242,19 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
+      {"__is_function", CPTK_IS_FUNCTION, false, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
-      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
       25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
-      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
-      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 56
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
+      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
+      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      57
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 29/39] libstdc++: Optimize is_pointer trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (27 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                         ` (10 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (28 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                         ` (9 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_arithmetic.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 184 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_arithmetic.C    |  33 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |   6 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   4 +-
 libstdc++-v3/include/c_global/cmath         |  48 ++---
 libstdc++-v3/include/c_std/cmath            |  24 +--
 libstdc++-v3/include/tr1/cmath              |  24 +--
 13 files changed, 193 insertions(+), 146 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 07a333ea826..5493f38bcbb 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -40,6 +40,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false
 "__is_abstract", CPTK_IS_ABSTRACT, false, false, false
 "__is_aggregate", CPTK_IS_AGGREGATE, false, false, false
+"__is_arithmetic", CPTK_IS_ARITHMETIC, false, false, false
 "__is_array", CPTK_IS_ARRAY, false, false, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false
 "__is_base_of", CPTK_IS_BASE_OF, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 011e454760c..b6dcb19cefb 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 97, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
-       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
-      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
-      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
+        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
+       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
+      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104
     };
   unsigned int hval = len;
 
@@ -118,130 +118,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 58,
+      TOTAL_KEYWORDS = 59,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 103
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, false, false, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_arithmetic", CPTK_IS_ARITHMETIC, false, false, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, false, false, false}
     };
 
@@ -249,12 +251,12 @@ cp_trait_lookup::find (const char *str, size_t len)
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
-      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      57
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
+      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
+      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
+      -1, -1, 57, -1, -1, 58
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 31/39] libstdc++: Optimize is_arithmetic trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (29 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
                         ` (8 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 32/39] libstdc++: Optimize is_fundamental trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (30 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 33/39] libstdc++: Optimize is_compound " Ken Matsui
                         ` (7 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 33/39] libstdc++: Optimize is_compound trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (31 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
                         ` (6 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 34/39] c++: Implement __is_unsigned built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (32 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 33/39] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                         ` (5 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unsigned.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNSIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 118 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_unsigned.C   |  47 +++++++++
 7 files changed, 120 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5493f38bcbb..c39b9d9007a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -75,6 +75,7 @@ struct cp_trait {
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false
 "__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false
 "__is_union", CPTK_IS_UNION, false, false, false
+"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false
 "__is_volatile", CPTK_IS_VOLATILE, false, false, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b6dcb19cefb..635c9a3a0e5 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 97, duplicates = 0 */
+/* maximum key range = 129, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
-        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
-       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
-      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
+       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
+       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
+      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136
     };
   unsigned int hval = len;
 
@@ -118,46 +118,44 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 59,
+      TOTAL_KEYWORDS = 60,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 103
+      MAX_HASH_VALUE = 135
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, false, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, false, false, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, false, false, false},
 #line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
@@ -167,11 +165,11 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
@@ -182,7 +180,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
 #line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+      {"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
@@ -209,6 +207,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, false, false, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
@@ -225,8 +225,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
 #line 71 "../../gcc/cp/cp-trait.gperf"
@@ -244,19 +244,23 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, false, false, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, false, false, false}
+      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
-      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
-      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
+       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
+      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
       -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58
+      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 35/39] libstdc++: Optimize is_unsigned trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (33 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                         ` (4 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 36/39] c++, libstdc++: Implement __is_signed built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (34 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
                         ` (3 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_signed.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 211 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_signed.C         |  47 +++++
 gcc/testsuite/g++.dg/tm/pr46567.C            |  12 +-
 libstdc++-v3/include/bits/charconv.h         |   2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |   6 +-
 libstdc++-v3/include/bits/uniform_int_dist.h |   4 +-
 libstdc++-v3/include/ext/numeric_traits.h    |  18 +-
 12 files changed, 186 insertions(+), 126 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index c39b9d9007a..67a1e37d754 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -67,6 +67,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
 "__is_reference", CPTK_IS_REFERENCE, false, false, false
 "__is_same", CPTK_IS_SAME, true, false, false
+"__is_signed", CPTK_IS_SIGNED, false, false, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false
 "__is_trivial", CPTK_IS_TRIVIAL, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 635c9a3a0e5..dd94ac56fec 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -56,7 +56,7 @@ struct cp_trait {
   bool variadic;
   bool type;
 };
-/* maximum key range = 129, duplicates = 0 */
+/* maximum key range = 119, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -71,32 +71,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
-       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
-       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
-      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
+       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
+       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
+      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126
     };
   unsigned int hval = len;
 
@@ -118,149 +118,150 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 60,
+      TOTAL_KEYWORDS = 61,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 135
+      MAX_HASH_VALUE = 125
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, false, false, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, true, false, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, false, false, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, true, false, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
 #line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_signed", CPTK_IS_SIGNED, false, false, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, true, false, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
-#line 37 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
-#line 36 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, false, false, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, false, false, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, false, false, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
-      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
+       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
+      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
+      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
+      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
+      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 37/39] libstdc++: Optimize is_signed trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (35 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                         ` (2 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 38/39] c++, libstdc++: Implement __is_scalar built-in trait
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (36 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10  9:46       ` [PATCH v15 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scalar.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCALAR.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 186 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_scalar.C        |  31 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  10 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   8 +-
 libstdc++-v3/include/bits/valarray_array.h  |   2 +-
 12 files changed, 150 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 67a1e37d754..654da0568ec 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -67,6 +67,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false
 "__is_reference", CPTK_IS_REFERENCE, false, false, false
 "__is_same", CPTK_IS_SAME, true, false, false
+"__is_scalar", CPTK_IS_SCALAR, false, false, false
 "__is_signed", CPTK_IS_SIGNED, false, false, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index dd94ac56fec..3c13835a8df 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,10 +80,10 @@ cp_trait_lookup::hash (const char *str, size_t len)
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
-       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
-       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
-      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  40, 126,  25,  21,  50,
+        0,   0,  30,  10, 126,   0, 126, 126,  25,   5,
+       50,   0,  61, 126,  10,  10,   5,   0,  15, 126,
+      126,   5, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
@@ -118,7 +118,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 61,
+      TOTAL_KEYWORDS = 62,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -127,141 +127,143 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, false, false, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, false, false, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, false, false, false},
 #line 84 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+      {"__remove_cv", CPTK_REMOVE_CV, false, false, true},
 #line 85 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, false, false, true},
+#line 90 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false},
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, false, false, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, false, false, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, false, false, true},
-#line 91 "../../gcc/cp/cp-trait.gperf"
+#line 92 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, false, false, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer", CPTK_IS_POINTER, false, false, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false},
 #line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, true, false, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, false, false, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, false, false, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, false, false, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, true, false, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, false, false, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, true, false, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_signed", CPTK_IS_SIGNED, false, false, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, false, true, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, false, false, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, true, false, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, false, false, false},
-#line 32 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
-#line 33 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, false, false, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
+#line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, true, false, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, false, false, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, false, false, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, false, false, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
+#line 89 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, false, false, true},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, false, false, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scalar", CPTK_IS_SCALAR, false, false, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, false, false, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, false, false, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, true, false, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, true, false, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, true, false, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, false, false, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, false, false, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, false, false, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, false, false, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, false, false, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, false, false, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, false, false, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, false, false, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, false, false, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, false, false, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, false, false, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, false, false, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, false, false, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, false, false, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, false, false, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, false, false, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, false, false, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, false, false, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, false, false, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, true, false, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, true, false, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, false, true, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, false, true, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, false, false, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, false, false, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, false, false, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, true, false, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, false, false, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, false, false, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, true, false, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, false, true, false},
-#line 89 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, true, false, false}
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, false, false, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
-      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
-      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
-      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
-      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5,  6,  7,  8,  9, -1, -1, -1, 10, 11, -1, 12, 13,
+      14, 15, 16, 17, -1, 18, -1, 19, 20, 21, 22, 23, 24, 25,
+      26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
+      -1, -1, 38, -1, 39, -1, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, 45, -1, 46, 47, 48, -1, -1, 49, 50, 51, 52, -1, -1,
+      -1, 53, -1, -1, -1, -1, 54, -1, -1, 55, -1, -1, -1, -1,
+      56, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, 58, -1,
+      -1, -1, -1, -1, 59, -1, 60, -1, -1, -1, -1, -1, -1, 61
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v15 39/39] libstdc++: Optimize is_scalar trait performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (37 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-10  9:46       ` Ken Matsui
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10  9:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 00/39] Optimize type traits performance
  2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
                         ` (38 preceding siblings ...)
  2023-10-10  9:46       ` [PATCH v15 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-10 22:09       ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
                           ` (39 more replies)
  39 siblings, 40 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v16:

	* Rebased on top of trunk
	* Improved clarity of the commit message
	* Simplified Make-lang.in and gperf struct

Changes in v15:

	* Rebased on top of trunk
	* Use gperf to look up traits instead of enum rid

Changes in v14:

	* Added padding calculation to the commit message

Changes in v13:

	* Fixed ambiguous commit message and comment

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (39):
  c++: Sort built-in identifiers alphabetically
  c-family, c++: Look up built-in traits through gperf
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc                      |  12 +-
 gcc/c-family/c-common.h                       |   7 +-
 gcc/cp/Make-lang.in                           |  24 ++
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-objcp-common.cc                     |   6 +-
 gcc/cp/cp-trait-head.in                       |  30 ++
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/cp-trait.gperf                         |  91 ++++++
 gcc/cp/cp-trait.h                             | 285 ++++++++++++++++++
 gcc/cp/parser.cc                              |  70 ++---
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 +++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 +++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 44 files changed, 1801 insertions(+), 298 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 01/39] c++: Sort built-in identifiers alphabetically
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
                           ` (38 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in identifiers alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in identifiers
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in identifiers
	alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-11 20:09           ` Patrick Palka
  2023-10-10 22:09         ` [PATCH v16 03/39] c++: Implement __is_const built-in trait Ken Matsui
                           ` (37 subsequent siblings)
  39 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Since RID_MAX soon reaches 255 and all traits are used approximately once in
a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
	and RID_TRAIT_TYPE instead.
	* c-common.h (enum rid): Remove all existing RID values for traits.
	Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.

gcc/cp/ChangeLog:

	* Make-lang.in: Add targets to generate cp-trait.gperf and
	cp-trait.h.
	* cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
	for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
	type-yielding traits.  Use RID_TRAIT_TYPE instead.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Likewise, for expression-yielding
	traits.  Use RID_TRAIT_EXPR instead.
	(cp_parser_trait): Look up traits through gperf instead of enum rid.
	* cp-trait-head.in: New file.
	* cp-trait.gperf: New file.
	* cp-trait.h: New file.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |  12 +-
 gcc/c-family/c-common.h   |   7 +-
 gcc/cp/Make-lang.in       |  24 ++++
 gcc/cp/cp-objcp-common.cc |   6 +-
 gcc/cp/cp-trait-head.in   |  30 +++++
 gcc/cp/cp-trait.gperf     |  74 ++++++++++++
 gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
 gcc/cp/parser.cc          |  70 ++++-------
 8 files changed, 412 insertions(+), 58 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..f219ccd29e5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
+#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_EXPR,	D_CXXONLY },
 #include "cp/cp-trait.def"
-#undef DEFTRAIT
+#undef DEFTRAIT_EXPR
   /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
+  { "__is_same_as",	RID_TRAIT_EXPR,	D_CXXONLY },
+#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_TYPE,	D_CXXONLY },
+#include "cp/cp-trait.def"
+#undef DEFTRAIT_TYPE
 
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..a1a641f4175 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,10 +168,9 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
+  /* C++ traits, defined in cp-trait.def.  */
+  RID_TRAIT_EXPR,
+  RID_TRAIT_TYPE,
 
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2727fb7f8cc..8d4e3a1f594 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -34,6 +34,8 @@
 # - the compiler proper (eg: cc1plus)
 # - define the names for selecting the language in LANGUAGES.
 
+AWK = @AWK@
+
 # Actual names to use when installing a native compiler.
 CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
 GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,28 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+# We always need the dependency on the .gperf file because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from a cp-trait.def file.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait.def $(srcdir)/cp/cp-trait-head.in
+	cat $(srcdir)/cp/cp-trait-head.in > $@
+	$(AWK) -F', *' '/^DEFTRAIT_/ { \
+		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+		gsub(/\)/, "", $$3); \
+		print $$2", CPTK_" $$1", "$$3", "type; \
+	}' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..c414d8f5a13 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -434,10 +434,8 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
+    case RID_TRAIT_EXPR:
+    case RID_TRAIT_TYPE:
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
new file mode 100644
index 00000000000..9357eea1238
--- /dev/null
+++ b/gcc/cp/cp-trait-head.in
@@ -0,0 +1,30 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
new file mode 100644
index 00000000000..47e3c1af499
--- /dev/null
+++ b/gcc/cp/cp-trait.gperf
@@ -0,0 +1,74 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
+"__is_abstract", CPTK_IS_ABSTRACT, 1, false
+"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
+"__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_class", CPTK_IS_CLASS, 1, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
+"__is_empty", CPTK_IS_EMPTY, 1, false
+"__is_enum", CPTK_IS_ENUM, 1, false
+"__is_final", CPTK_IS_FINAL, 1, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
+"__is_pod", CPTK_IS_POD, 1, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_same", CPTK_IS_SAME, 2, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
+"__is_trivial", CPTK_IS_TRIVIAL, 1, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_union", CPTK_IS_UNION, 1, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
+"__remove_cv", CPTK_REMOVE_CV, 1, true
+"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
+"__bases", CPTK_BASES, 1, true
+"__direct_bases", CPTK_DIRECT_BASES, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
new file mode 100644
index 00000000000..97ba8492d15
--- /dev/null
+++ b/gcc/cp/cp-trait.h
@@ -0,0 +1,247 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned char asso_values[] =
+    {
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
+       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
+      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
+      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        break;
+    }
+  return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 45,
+      MIN_WORD_LENGTH = 7,
+      MAX_WORD_LENGTH = 37,
+      MIN_HASH_VALUE = 7,
+      MAX_HASH_VALUE = 85
+    };
+
+  static const struct cp_trait wordlist[] =
+    {
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__bases", CPTK_BASES, 1, true},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+    };
+
+  static const signed char lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
+       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..432c43400ab 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "contracts.h"
 #include "bitmap.h"
 #include "builtins.h"
+#include "cp-trait.h"
 
 \f
 /* The lexer.  */
@@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* C++20 extensions.  */
     case RID_CONSTINIT:
     case RID_CONSTEVAL:
-      return true;
-
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
+      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
+    case RID_TRAIT_TYPE:
       return true;
 
     default:
@@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, tree);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
+	case RID_TRAIT_EXPR:
+	  return cp_parser_trait (parser, token->u.value);
 
 	// C++ concepts
 	case RID_REQUIRES:
@@ -11033,28 +11027,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, tree keyword)
 {
-  cp_trait_kind kind;
-  tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
+  const char* keyword_str = IDENTIFIER_POINTER (keyword);
+  int keyword_len = IDENTIFIER_LENGTH (keyword);
+  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
 
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  tree type1, type2 = NULL_TREE;
+  bool binary = (trait->arity == 2);
+  bool variadic = (trait->arity == -1);
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11044,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11060,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11075,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11139,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,11 +20062,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    case RID_TRAIT_TYPE:
+      type = cp_parser_trait (parser, token->u.value);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 03/39] c++: Implement __is_const built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
                           ` (36 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

	* Make-lang.in: Update key positions for gperf, based on
	automatically computed values.
	* cp-trait.def: Define __is_const.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/Make-lang.in                      |   2 +-
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 202 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_const.C      |  19 +++
 8 files changed, 135 insertions(+), 100 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 8d4e3a1f594..b6e6cefca53 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -194,7 +194,7 @@ $(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
 else
 $(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
 endif
-	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+	gperf -o -C -E -k '6,8' -D -N 'find' -L C++ \
 		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
 
 # The cp-trait.gperf file itself is generated from a cp-trait.def file.
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47e3c1af499..47a5ec9ee6f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
+"__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
 "__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
 "__is_empty", CPTK_IS_EMPTY, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 97ba8492d15..c9005eee1ff 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -1,5 +1,5 @@
 /* C++ code produced by gperf version 3.1 */
-/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+/* Command-line: gperf -o -C -E -k 6,8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 79, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
-       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
-      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
-      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
+      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
+      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -104,6 +104,8 @@ cp_trait_lookup::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
       case 7:
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
         break;
     }
   return hval;
@@ -114,116 +116,118 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 85
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
-       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
-      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
-      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
-      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
+      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
+      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
+      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
+      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 04/39] libstdc++: Optimize is_const trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (2 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 03/39] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
                           ` (35 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 05/39] c++: Implement __is_volatile built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (3 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
                           ` (34 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_volatile.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 ++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/cp-trait.gperf                    |  1 +
 gcc/cp/cp-trait.h                        | 38 +++++++++++++-----------
 gcc/cp/semantics.cc                      |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C   | 19 ++++++++++++
 7 files changed, 51 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47a5ec9ee6f..ea7abda6c75 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index c9005eee1ff..f462794d5db 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
       40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
       96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,27 +125,29 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
@@ -159,9 +161,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -215,19 +217,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
-      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
-      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
-      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
-      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
+      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
+      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 06/39] libstdc++: Optimize is_volatile trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (4 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 07/39] c++: Implement __is_array built-in trait Ken Matsui
                           ` (33 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 07/39] c++: Implement __is_array built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (5 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:09         ` [PATCH v16 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
                           ` (32 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 148 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_array.C      |  28 +++++
 7 files changed, 116 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ea7abda6c75..fb162cac164 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f462794d5db..526e63dec42 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
-      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
-      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
+       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
+       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,108 +116,110 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 47,
+      TOTAL_KEYWORDS = 48,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -226,10 +228,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
       14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
-      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 47
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 08/39] libstdc++: Optimize is_array trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (6 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 07/39] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-10 22:09         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                           ` (31 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 09/39] c++: Implement __is_unbounded_array built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (7 preceding siblings ...)
  2023-10-10 22:09         ` [PATCH v16 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                           ` (30 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unbounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNBOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 42 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 ++++++++++++++++
 7 files changed, 71 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index fb162cac164..a894fc8c74c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 526e63dec42..47060ffbbef 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 48,
+      TOTAL_KEYWORDS = 49,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,30 +125,32 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
@@ -161,9 +163,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -219,21 +221,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
-      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
+      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
+      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 47
+      -1, -1, -1, 48
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 10/39] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (8 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
                           ` (29 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 11/39] c++: Implement __is_bounded_array built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (9 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                           ` (28 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_bounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_BOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |  3 +
 gcc/cp/cp-trait.def                         |  1 +
 gcc/cp/cp-trait.gperf                       |  1 +
 gcc/cp/cp-trait.h                           | 86 +++++++++++----------
 gcc/cp/semantics.cc                         |  4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  3 +
 gcc/testsuite/g++.dg/ext/is_bounded_array.C | 38 +++++++++
 7 files changed, 94 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index a894fc8c74c..90fcdc01de6 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false
 "__is_class", CPTK_IS_CLASS, 1, false
 "__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 47060ffbbef..f22a6e93618 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
        50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
       116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 49,
+      TOTAL_KEYWORDS = 50,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,54 +125,56 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -181,7 +183,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -191,27 +193,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
@@ -219,9 +221,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -230,12 +232,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
-      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
+      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
+      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 48
+      -1, -1, -1, 49
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 12/39] libstdc++: Optimize is_bounded_array trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (10 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                           ` (27 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 13/39] c++: Implement __is_scoped_enum built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (11 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                           ` (26 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scoped_enum.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCOPED_ENUM.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                      |   3 +
 gcc/cp/cp-trait.def                       |   1 +
 gcc/cp/cp-trait.gperf                     |   1 +
 gcc/cp/cp-trait.h                         | 161 +++++++++++-----------
 gcc/cp/semantics.cc                       |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |   3 +
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C |  67 +++++++++
 7 files changed, 160 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90fcdc01de6..f3fd82ba549 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -59,6 +59,7 @@ struct cp_trait {
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f22a6e93618..9c18165eb68 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
-       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
-      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
+      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
+      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
+      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,56 +116,60 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 50,
+      TOTAL_KEYWORDS = 51,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -173,22 +177,18 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
@@ -197,47 +197,48 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
-      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 49
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
+      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
+      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
+      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
+      50
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 14/39] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (12 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
                           ` (25 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 15/39] c++: Implement __is_member_pointer built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (13 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                           ` (24 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_MEMBER_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 153 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_member_pointer.C |  30 ++++
 7 files changed, 120 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index f3fd82ba549..3775b11283d 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 9c18165eb68..dfd60cec6e6 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 111, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
-      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
-      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
-      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
+       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
+       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
+      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118
     };
   unsigned int hval = len;
 
@@ -116,69 +116,67 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 51,
+      TOTAL_KEYWORDS = 52,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 117
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -187,58 +185,63 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
-      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
-      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
-      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
-      50
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
+      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
+      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
+      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
+      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
+      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, 51
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 16/39] libstdc++: Optimize is_member_pointer trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (14 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                           ` (23 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 17/39] c++: Implement __is_member_function_pointer built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (15 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                           ` (22 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_function_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_FUNCTION_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |   3 +
 gcc/cp/cp-trait.def                           |   1 +
 gcc/cp/cp-trait.gperf                         |   1 +
 gcc/cp/cp-trait.h                             | 176 +++++++++---------
 gcc/cp/semantics.cc                           |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |   3 +
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 7 files changed, 131 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 3775b11283d..b28efbab322 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index dfd60cec6e6..d3d4bdf9799 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 111, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
-       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
-       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
-      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
+      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
+      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
+      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -116,132 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 52,
+      TOTAL_KEYWORDS = 53,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 117
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
-      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
-      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
-      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
-      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
-      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, 51
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
+      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 18/39] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (16 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                           ` (21 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 19/39] c++: Implement __is_member_object_pointer built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (17 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                           ` (20 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_object_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_OBJECT_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 +
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 62 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 +
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++
 7 files changed, 74 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index b28efbab322..32199a1fe9a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
+"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index d3d4bdf9799..799fe2b792f 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 53,
+      TOTAL_KEYWORDS = 54,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,57 +125,57 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,25 +185,25 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
@@ -211,12 +211,14 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
@@ -229,7 +231,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -240,8 +242,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
       -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
-      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
+      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 20/39] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (18 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 21/39] c++: Implement __is_reference built-in trait Ken Matsui
                           ` (19 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 21/39] c++: Implement __is_reference built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (19 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
                           ` (18 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_reference.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 113 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_reference.C  |  34 +++++++
 7 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 32199a1fe9a..5989b84727f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 799fe2b792f..f0b4f96d4a9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 94, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
-      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
-      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
-      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
+       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
+       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
+      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   unsigned int hval = len;
 
@@ -116,58 +116,58 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 54,
+      TOTAL_KEYWORDS = 55,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 100
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -175,7 +175,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,7 +185,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -207,15 +207,13 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
@@ -223,6 +221,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,8 +231,10 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false}
     };
 
   static const signed char lookup[] =
@@ -241,9 +243,10 @@ cp_trait_lookup::find (const char *str, size_t len)
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
+      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      -1, -1, 54
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 22/39] libstdc++: Optimize is_reference trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (20 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 21/39] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 23/39] c++: Implement __is_function built-in trait Ken Matsui
                           ` (17 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 23/39] c++: Implement __is_function built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (21 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
                           ` (16 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_function.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 143 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_function.C   |  58 +++++++++
 7 files changed, 143 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5989b84727f..771242a7f45 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -50,6 +50,7 @@ struct cp_trait {
 "__is_empty", CPTK_IS_EMPTY, 1, false
 "__is_enum", CPTK_IS_ENUM, 1, false
 "__is_final", CPTK_IS_FINAL, 1, false
+"__is_function", CPTK_IS_FUNCTION, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f0b4f96d4a9..b6db58e93c9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 94, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
-       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
-       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
-      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
+       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
+       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
+      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,113 +116,113 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 55,
+      TOTAL_KEYWORDS = 56,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 100
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,10 +231,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false}
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
@@ -242,11 +244,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
-      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      -1, -1, 54
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
+      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 55
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 24/39] libstdc++: Optimize is_function trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (22 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 23/39] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 25/39] libstdc++: Optimize is_object " Ken Matsui
                           ` (15 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 25/39] libstdc++: Optimize is_object trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (23 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
                           ` (14 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 26/39] c++: Implement __remove_pointer built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (24 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 25/39] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                           ` (13 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/cp-trait.gperf                     |  1 +
 gcc/cp/cp-trait.h                         | 32 +++++++-------
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 6 files changed, 78 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 771242a7f45..8fbd67788d5 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -77,6 +77,7 @@ struct cp_trait {
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
 "__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_pointer", CPTK_REMOVE_POINTER, 1, true
 "__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
 "__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
 "__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b6db58e93c9..ad2c2a2d250 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 56,
+      TOTAL_KEYWORDS = 57,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,7 +125,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
@@ -137,17 +137,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
@@ -235,21 +237,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
-      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 55
+       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
+      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
+      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
+      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 56
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 27/39] libstdc++: Optimize remove_pointer trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (25 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                           ` (12 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 28/39] c++, libstdc++: Implement __is_pointer built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (26 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
                           ` (11 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 155 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_pointer.C       |  51 +++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  22 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C   |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   6 +-
 libstdc++-v3/include/bits/deque.tcc         |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   6 +-
 13 files changed, 165 insertions(+), 101 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 8fbd67788d5..5d40e04f91c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
+"__is_pointer", CPTK_IS_POINTER, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ad2c2a2d250..ab783b161c7 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
-       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
-       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
-      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
+       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
+      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
+      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,78 +116,78 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 57,
+      TOTAL_KEYWORDS = 58,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -205,23 +205,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_array", CPTK_IS_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
@@ -236,22 +240,19 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
-      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
       25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
-      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
-      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 56
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
+      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
+      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      57
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 29/39] libstdc++: Optimize is_pointer trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (27 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                           ` (10 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (28 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                           ` (9 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_arithmetic.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 184 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_arithmetic.C    |  33 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |   6 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   4 +-
 libstdc++-v3/include/c_global/cmath         |  48 ++---
 libstdc++-v3/include/c_std/cmath            |  24 +--
 libstdc++-v3/include/tr1/cmath              |  24 +--
 13 files changed, 193 insertions(+), 146 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5d40e04f91c..9050c36f105 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ab783b161c7..31fd5075f2d 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 97, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
-       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
-      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
-      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
+        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
+       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
+      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104
     };
   unsigned int hval = len;
 
@@ -116,130 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 58,
+      TOTAL_KEYWORDS = 59,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 103
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
@@ -247,12 +249,12 @@ cp_trait_lookup::find (const char *str, size_t len)
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
-      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      57
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
+      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
+      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
+      -1, -1, 57, -1, -1, 58
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 31/39] libstdc++: Optimize is_arithmetic trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (29 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
                           ` (8 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 32/39] libstdc++: Optimize is_fundamental trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (30 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 33/39] libstdc++: Optimize is_compound " Ken Matsui
                           ` (7 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 33/39] libstdc++: Optimize is_compound trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (31 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
                           ` (6 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 34/39] c++: Implement __is_unsigned built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (32 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 33/39] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                           ` (5 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unsigned.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNSIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 118 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_unsigned.C   |  47 +++++++++
 7 files changed, 120 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 9050c36f105..90d05bca5c1 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -74,6 +74,7 @@ struct cp_trait {
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_unsigned", CPTK_IS_UNSIGNED, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 31fd5075f2d..75ab2b5edfa 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 97, duplicates = 0 */
+/* maximum key range = 129, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
-        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
-       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
-      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
+       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
+       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
+      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136
     };
   unsigned int hval = len;
 
@@ -116,46 +116,44 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 59,
+      TOTAL_KEYWORDS = 60,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 103
+      MAX_HASH_VALUE = 135
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
@@ -165,11 +163,11 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -180,7 +178,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
 #line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -207,6 +205,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
@@ -223,8 +223,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 70 "../../gcc/cp/cp-trait.gperf"
@@ -242,19 +242,23 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
-      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
-      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
+       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
+      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
       -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58
+      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 35/39] libstdc++: Optimize is_unsigned trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (33 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                           ` (4 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 36/39] c++, libstdc++: Implement __is_signed built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (34 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
                           ` (3 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_signed.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 211 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_signed.C         |  47 +++++
 gcc/testsuite/g++.dg/tm/pr46567.C            |  12 +-
 libstdc++-v3/include/bits/charconv.h         |   2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |   6 +-
 libstdc++-v3/include/bits/uniform_int_dist.h |   4 +-
 libstdc++-v3/include/ext/numeric_traits.h    |  18 +-
 12 files changed, 186 insertions(+), 126 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90d05bca5c1..de0ba162e7a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 75ab2b5edfa..6d1078de2fe 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 129, duplicates = 0 */
+/* maximum key range = 119, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
-       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
-       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
-      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
+       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
+       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
+      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126
     };
   unsigned int hval = len;
 
@@ -116,149 +116,150 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 60,
+      TOTAL_KEYWORDS = 61,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 135
+      MAX_HASH_VALUE = 125
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_signed", CPTK_IS_SIGNED, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 36 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 37 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
-      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
+       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
+      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
+      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
+      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
+      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 37/39] libstdc++: Optimize is_signed trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (35 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                           ` (2 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 38/39] c++, libstdc++: Implement __is_scalar built-in trait
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (36 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-10 22:10         ` [PATCH v16 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scalar.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCALAR.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 186 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_scalar.C        |  31 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  10 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   8 +-
 libstdc++-v3/include/bits/valarray_array.h  |   2 +-
 12 files changed, 150 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index de0ba162e7a..ef51c713c58 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scalar", CPTK_IS_SCALAR, 1, false
 "__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 6d1078de2fe..8c68af420f9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -78,10 +78,10 @@ cp_trait_lookup::hash (const char *str, size_t len)
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
-       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
-       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
-      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  40, 126,  25,  21,  50,
+        0,   0,  30,  10, 126,   0, 126, 126,  25,   5,
+       50,   0,  61, 126,  10,  10,   5,   0,  15, 126,
+      126,   5, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 61,
+      TOTAL_KEYWORDS = 62,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,141 +125,143 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 89 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_signed", CPTK_IS_SIGNED, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 33 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 32 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scalar", CPTK_IS_SCALAR, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
-      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
-      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
-      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
-      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5,  6,  7,  8,  9, -1, -1, -1, 10, 11, -1, 12, 13,
+      14, 15, 16, 17, -1, 18, -1, 19, 20, 21, 22, 23, 24, 25,
+      26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
+      -1, -1, 38, -1, 39, -1, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, 45, -1, 46, 47, 48, -1, -1, 49, 50, 51, 52, -1, -1,
+      -1, 53, -1, -1, -1, -1, 54, -1, -1, 55, -1, -1, -1, -1,
+      56, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, 58, -1,
+      -1, -1, -1, -1, 59, -1, 60, -1, -1, -1, -1, -1, -1, 61
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v16 39/39] libstdc++: Optimize is_scalar trait performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (37 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-10 22:10         ` Ken Matsui
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-10 22:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf
  2023-10-10 22:09         ` [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-11 20:09           ` Patrick Palka
  2023-10-11 21:34             ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-11 20:09 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, jason

On Tue, 10 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all traits are used approximately once in
> a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
> RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.

Nice!  This looks good to me, but I wonder what the corresponding
ridpointers entry should be for RID_TRAIT_TYPE and RID_TRAIT_EXPR?  It
seems we currently assume every rid code has a unique canonical spelling
which we keep in ridpointers[RID_FOO], but that's of course not the case
for RID_TRAIT_TYPE and RID_TRAIT_EXPR.  Maybe we should make
init_reswords() keep the ridpointers entry empty for RID_TRAIT_EXPR and
RID_TRAIT_TYPE?

> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
> 	and RID_TRAIT_TYPE instead.
> 	* c-common.h (enum rid): Remove all existing RID values for traits.
> 	Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 
> gcc/cp/ChangeLog:
> 
> 	* Make-lang.in: Add targets to generate cp-trait.gperf and
> 	cp-trait.h.
> 	* cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
> 	for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 	* parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
> 	type-yielding traits.  Use RID_TRAIT_TYPE instead.
> 	(cp_parser_simple_type_specifier): Likewise.
> 	(cp_parser_primary_expression): Likewise, for expression-yielding
> 	traits.  Use RID_TRAIT_EXPR instead.
> 	(cp_parser_trait): Look up traits through gperf instead of enum rid.
> 	* cp-trait-head.in: New file.
> 	* cp-trait.gperf: New file.
> 	* cp-trait.h: New file.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |  12 +-
>  gcc/c-family/c-common.h   |   7 +-
>  gcc/cp/Make-lang.in       |  24 ++++
>  gcc/cp/cp-objcp-common.cc |   6 +-
>  gcc/cp/cp-trait-head.in   |  30 +++++
>  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
>  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
>  gcc/cp/parser.cc          |  70 ++++-------
>  8 files changed, 412 insertions(+), 58 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..f219ccd29e5 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",		RID_WCHAR,	D_CXXONLY },
>    { "while",		RID_WHILE,	0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,		RID_##CODE,	D_CXXONLY },
> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> +  { NAME,		RID_TRAIT_EXPR,	D_CXXONLY },
>  #include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +#undef DEFTRAIT_EXPR
>    /* An alias for __is_same.  */
> -  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
> +  { "__is_same_as",	RID_TRAIT_EXPR,	D_CXXONLY },
> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> +  { NAME,		RID_TRAIT_TYPE,	D_CXXONLY },
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT_TYPE
>  
>    /* C++ transactional memory.  */
>    { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..a1a641f4175 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,10 +168,9 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +  /* C++ traits, defined in cp-trait.def.  */
> +  RID_TRAIT_EXPR,
> +  RID_TRAIT_TYPE,
>  
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..8d4e3a1f594 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
>  # - the compiler proper (eg: cc1plus)
>  # - define the names for selecting the language in LANGUAGES.
>  
> +AWK = @AWK@
> +
>  # Actual names to use when installing a native compiler.
>  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
>  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,28 @@ endif
>  # This is the file that depends on the generated header file.
>  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>  
> +# We always need the dependency on the .gperf file because it itself is generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> +	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> +		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf file itself is generated from a cp-trait.def file.
> +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait.def $(srcdir)/cp/cp-trait-head.in
> +	cat $(srcdir)/cp/cp-trait-head.in > $@
> +	$(AWK) -F', *' '/^DEFTRAIT_/ { \
> +		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> +		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> +		gsub(/\)/, "", $$3); \
> +		print $$2", CPTK_" $$1", "$$3", "type; \
> +	}' $(srcdir)/cp/cp-trait.def >> $@
> +
> +# This is the file that depends on the generated header file.
> +cp/parser.o: $(srcdir)/cp/cp-trait.h
> +
>  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
>  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..c414d8f5a13 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -434,10 +434,8 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> +    case RID_TRAIT_EXPR:
> +    case RID_TRAIT_TYPE:
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> new file mode 100644
> index 00000000000..9357eea1238
> --- /dev/null
> +++ b/gcc/cp/cp-trait-head.in
> @@ -0,0 +1,30 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> new file mode 100644
> index 00000000000..47e3c1af499
> --- /dev/null
> +++ b/gcc/cp/cp-trait.gperf
> @@ -0,0 +1,74 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> +"__is_class", CPTK_IS_CLASS, 1, false
> +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> +"__is_empty", CPTK_IS_EMPTY, 1, false
> +"__is_enum", CPTK_IS_ENUM, 1, false
> +"__is_final", CPTK_IS_FINAL, 1, false
> +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> +"__is_pod", CPTK_IS_POD, 1, false
> +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> +"__is_same", CPTK_IS_SAME, 2, false
> +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> +"__is_union", CPTK_IS_UNION, 1, false
> +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> +"__remove_cv", CPTK_REMOVE_CV, 1, true
> +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> +"__bases", CPTK_BASES, 1, true
> +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> new file mode 100644
> index 00000000000..97ba8492d15
> --- /dev/null
> +++ b/gcc/cp/cp-trait.h
> @@ -0,0 +1,247 @@
> +/* C++ code produced by gperf version 3.1 */
> +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> +
> +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> +/* The character set is not based on ISO-646.  */
> +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> +#endif
> +
> +#line 4 "../../gcc/cp/cp-trait.gperf"
> +
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +#line 23 "../../gcc/cp/cp-trait.gperf"
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +/* maximum key range = 79, duplicates = 0 */
> +
> +class cp_trait_lookup
> +{
> +private:
> +  static inline unsigned int hash (const char *str, size_t len);
> +public:
> +  static const struct cp_trait *find (const char *str, size_t len);
> +};
> +
> +inline unsigned int
> +cp_trait_lookup::hash (const char *str, size_t len)
> +{
> +  static const unsigned char asso_values[] =
> +    {
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86
> +    };
> +  unsigned int hval = len;
> +
> +  switch (hval)
> +    {
> +      default:
> +        hval += asso_values[static_cast<unsigned char>(str[7])];
> +      /*FALLTHROUGH*/
> +      case 7:
> +        break;
> +    }
> +  return hval;
> +}
> +
> +const struct cp_trait *
> +cp_trait_lookup::find (const char *str, size_t len)
> +{
> +  enum
> +    {
> +      TOTAL_KEYWORDS = 45,
> +      MIN_WORD_LENGTH = 7,
> +      MAX_WORD_LENGTH = 37,
> +      MIN_HASH_VALUE = 7,
> +      MAX_HASH_VALUE = 85
> +    };
> +
> +  static const struct cp_trait wordlist[] =
> +    {
> +#line 73 "../../gcc/cp/cp-trait.gperf"
> +      {"__bases", CPTK_BASES, 1, true},
> +#line 56 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pod", CPTK_IS_POD, 1, false},
> +#line 48 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> +#line 64 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_union", CPTK_IS_UNION, 1, false},
> +#line 44 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_class", CPTK_IS_CLASS, 1, false},
> +#line 60 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> +#line 41 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> +#line 72 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> +#line 43 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> +#line 40 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> +#line 58 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same", CPTK_IS_SAME, 2, false},
> +#line 42 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> +#line 59 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> +#line 30 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> +#line 63 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> +#line 39 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> +#line 61 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> +#line 57 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> +#line 71 "../../gcc/cp/cp-trait.gperf"
> +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> +#line 62 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> +#line 74 "../../gcc/cp/cp-trait.gperf"
> +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> +#line 51 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> +#line 33 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> +#line 31 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> +#line 55 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> +#line 52 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> +#line 54 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> +#line 32 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> +#line 53 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> +#line 50 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> +#line 67 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> +#line 36 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> +#line 68 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> +#line 34 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> +#line 69 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> +#line 37 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> +#line 35 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> +#line 49 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_final", CPTK_IS_FINAL, 1, false},
> +#line 47 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> +#line 46 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> +#line 45 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> +#line 66 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> +#line 65 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> +#line 70 "../../gcc/cp/cp-trait.gperf"
> +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> +#line 38 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> +    };
> +
> +  static const signed char lookup[] =
> +    {
> +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> +      -1, 44
> +    };
> +
> +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> +    {
> +      unsigned int key = hash (str, len);
> +
> +      if (key <= MAX_HASH_VALUE)
> +        {
> +          int index = lookup[key];
> +
> +          if (index >= 0)
> +            {
> +              const char *s = wordlist[index].name;
> +
> +              if (*str == *s && !strcmp (str + 1, s + 1))
> +                return &wordlist[index];
> +            }
> +        }
> +    }
> +  return 0;
> +}
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index f3abae716fe..432c43400ab 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "contracts.h"
>  #include "bitmap.h"
>  #include "builtins.h"
> +#include "cp-trait.h"
>  
>  \f
>  /* The lexer.  */
> @@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>        /* C++20 extensions.  */
>      case RID_CONSTINIT:
>      case RID_CONSTEVAL:
> -      return true;
> -
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> +      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
> +    case RID_TRAIT_TYPE:
>        return true;
>  
>      default:
> @@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, tree);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_OFFSETOF:
>  	  return cp_parser_builtin_offsetof (parser);
>  
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -	case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -	  return cp_parser_trait (parser, token->keyword);
> +	case RID_TRAIT_EXPR:
> +	  return cp_parser_trait (parser, token->u.value);
>  
>  	// C++ concepts
>  	case RID_REQUIRES:
> @@ -11033,28 +11027,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>  
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, tree keyword)
>  {
> -  cp_trait_kind kind;
> -  tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> +  const char* keyword_str = IDENTIFIER_POINTER (keyword);
> +  int keyword_len = IDENTIFIER_LENGTH (keyword);
> +  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
>  
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:			 \
> -      kind = CPTK_##CODE;		 \
> -      binary = (ARITY == 2);		 \
> -      variadic = (ARITY == -1);		 \
> -      type = (TCC == tcc_type);		 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  tree type1, type2 = NULL_TREE;
> +  bool binary = (trait->arity == 2);
> +  bool variadic = (trait->arity == -1);
>  
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -11063,12 +11044,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    cp_lexer_consume_token (parser->lexer);
>  
>    matching_parens parens;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      cp_parser_require (parser, CPP_LESS, RT_LESS);
>    else
>      parens.require_open (parser);
>  
> -  if (kind == CPTK_IS_DEDUCIBLE)
> +  if (trait->kind == CPTK_IS_DEDUCIBLE)
>      {
>        const cp_token* token = cp_lexer_peek_token (parser->lexer);
>        type1 = cp_parser_id_expression (parser,
> @@ -11079,7 +11060,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  				       /*optional_p=*/false);
>        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
>      }
> -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* __type_pack_element takes an expression as its first argument and uses
>         template-id syntax instead of function call syntax (for consistency
>         with Clang).  We special case these properties of __type_pack_element
> @@ -11094,7 +11075,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    if (type1 == error_mark_node)
>      return error_mark_node;
>  
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      {
>        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
>        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> @@ -11144,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>      }
>  
>    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* cp_parser_enclosed_template_argument_list above already took care
>         of parsing the closing '>'.  */;
>    else
> @@ -11158,17 +11139,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  
>    /* Complete the trait expression, which may mean either processing
>       the trait expr now or saving it for template instantiation.  */
> -  switch (kind)
> +  switch (trait->kind)
>      {
>      case CPTK_BASES:
>        return cp_expr (finish_bases (type1, false), trait_loc);
>      case CPTK_DIRECT_BASES:
>        return cp_expr (finish_bases (type1, true), trait_loc);
>      default:
> -      if (type)
> -	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> +      if (trait->type)
> +	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
>        else
> -	return finish_trait_expr (trait_loc, kind, type1, type2);
> +	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
>      }
>  }
>  
> @@ -20081,11 +20062,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>  
>        return type;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    case RID_TRAIT_TYPE:
> +      type = cp_parser_trait (parser, token->u.value);
>        if (decl_specs)
>  	cp_parser_set_decl_spec_type (decl_specs, type,
>  				      token,
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf
  2023-10-11 20:09           ` Patrick Palka
@ 2023-10-11 21:34             ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:34 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++, jason

On Wed, Oct 11, 2023 at 1:09 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Tue, 10 Oct 2023, Ken Matsui wrote:
>
> > Since RID_MAX soon reaches 255 and all traits are used approximately once in
> > a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
> > RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.
>
> Nice!  This looks good to me, but I wonder what the corresponding
> ridpointers entry should be for RID_TRAIT_TYPE and RID_TRAIT_EXPR?  It
> seems we currently assume every rid code has a unique canonical spelling
> which we keep in ridpointers[RID_FOO], but that's of course not the case
> for RID_TRAIT_TYPE and RID_TRAIT_EXPR.  Maybe we should make
> init_reswords() keep the ridpointers entry empty for RID_TRAIT_EXPR and
> RID_TRAIT_TYPE?
>

That makes sense. I will update this patch. Thank you for your review!

> >
> > gcc/c-family/ChangeLog:
> >
> >       * c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
> >       and RID_TRAIT_TYPE instead.
> >       * c-common.h (enum rid): Remove all existing RID values for traits.
> >       Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> >
> > gcc/cp/ChangeLog:
> >
> >       * Make-lang.in: Add targets to generate cp-trait.gperf and
> >       cp-trait.h.
> >       * cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
> >       for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> >       * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
> >       type-yielding traits.  Use RID_TRAIT_TYPE instead.
> >       (cp_parser_simple_type_specifier): Likewise.
> >       (cp_parser_primary_expression): Likewise, for expression-yielding
> >       traits.  Use RID_TRAIT_EXPR instead.
> >       (cp_parser_trait): Look up traits through gperf instead of enum rid.
> >       * cp-trait-head.in: New file.
> >       * cp-trait.gperf: New file.
> >       * cp-trait.h: New file.
> >
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/c-family/c-common.cc  |  12 +-
> >  gcc/c-family/c-common.h   |   7 +-
> >  gcc/cp/Make-lang.in       |  24 ++++
> >  gcc/cp/cp-objcp-common.cc |   6 +-
> >  gcc/cp/cp-trait-head.in   |  30 +++++
> >  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
> >  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
> >  gcc/cp/parser.cc          |  70 ++++-------
> >  8 files changed, 412 insertions(+), 58 deletions(-)
> >  create mode 100644 gcc/cp/cp-trait-head.in
> >  create mode 100644 gcc/cp/cp-trait.gperf
> >  create mode 100644 gcc/cp/cp-trait.h
> >
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index f044db5b797..f219ccd29e5 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
> > @@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
> >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> >    { "while",         RID_WHILE,      0 },
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > +  { NAME,            RID_TRAIT_EXPR, D_CXXONLY },
> >  #include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > +#undef DEFTRAIT_EXPR
> >    /* An alias for __is_same.  */
> > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > +  { "__is_same_as",  RID_TRAIT_EXPR, D_CXXONLY },
> > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > +  { NAME,            RID_TRAIT_TYPE, D_CXXONLY },
> > +#include "cp/cp-trait.def"
> > +#undef DEFTRAIT_TYPE
> >
> >    /* C++ transactional memory.  */
> >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 1fdba7ef3ea..a1a641f4175 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -168,10 +168,9 @@ enum rid
> >    RID_BUILTIN_LAUNDER,
> >    RID_BUILTIN_BIT_CAST,
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  RID_##CODE,
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > +  /* C++ traits, defined in cp-trait.def.  */
> > +  RID_TRAIT_EXPR,
> > +  RID_TRAIT_TYPE,
> >
> >    /* C++11 */
> >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > index 2727fb7f8cc..8d4e3a1f594 100644
> > --- a/gcc/cp/Make-lang.in
> > +++ b/gcc/cp/Make-lang.in
> > @@ -34,6 +34,8 @@
> >  # - the compiler proper (eg: cc1plus)
> >  # - define the names for selecting the language in LANGUAGES.
> >
> > +AWK = @AWK@
> > +
> >  # Actual names to use when installing a native compiler.
> >  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> >  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > @@ -186,6 +188,28 @@ endif
> >  # This is the file that depends on the generated header file.
> >  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> >
> > +# We always need the dependency on the .gperf file because it itself is generated.
> > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > +else
> > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > +endif
> > +     gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > +             $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > +
> > +# The cp-trait.gperf file itself is generated from a cp-trait.def file.
> > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait.def $(srcdir)/cp/cp-trait-head.in
> > +     cat $(srcdir)/cp/cp-trait-head.in > $@
> > +     $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > +             type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > +             gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > +             gsub(/\)/, "", $$3); \
> > +             print $$2", CPTK_" $$1", "$$3", "type; \
> > +     }' $(srcdir)/cp/cp-trait.def >> $@
> > +
> > +# This is the file that depends on the generated header file.
> > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > +
> >  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> >  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> >
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 93b027b80ce..c414d8f5a13 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -434,10 +434,8 @@ names_builtin_p (const char *name)
> >      case RID_BUILTIN_ASSOC_BARRIER:
> >      case RID_BUILTIN_BIT_CAST:
> >      case RID_OFFSETOF:
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > +    case RID_TRAIT_EXPR:
> > +    case RID_TRAIT_TYPE:
> >        return true;
> >      default:
> >        break;
> > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > new file mode 100644
> > index 00000000000..9357eea1238
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait-head.in
> > @@ -0,0 +1,30 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +%}
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > new file mode 100644
> > index 00000000000..47e3c1af499
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.gperf
> > @@ -0,0 +1,74 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +%}
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > +"__is_class", CPTK_IS_CLASS, 1, false
> > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > +"__is_enum", CPTK_IS_ENUM, 1, false
> > +"__is_final", CPTK_IS_FINAL, 1, false
> > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > +"__is_pod", CPTK_IS_POD, 1, false
> > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > +"__is_same", CPTK_IS_SAME, 2, false
> > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > +"__is_union", CPTK_IS_UNION, 1, false
> > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > +"__bases", CPTK_BASES, 1, true
> > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > new file mode 100644
> > index 00000000000..97ba8492d15
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.h
> > @@ -0,0 +1,247 @@
> > +/* C++ code produced by gperf version 3.1 */
> > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> > +
> > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > +/* The character set is not based on ISO-646.  */
> > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > +#endif
> > +
> > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > +
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +/* maximum key range = 79, duplicates = 0 */
> > +
> > +class cp_trait_lookup
> > +{
> > +private:
> > +  static inline unsigned int hash (const char *str, size_t len);
> > +public:
> > +  static const struct cp_trait *find (const char *str, size_t len);
> > +};
> > +
> > +inline unsigned int
> > +cp_trait_lookup::hash (const char *str, size_t len)
> > +{
> > +  static const unsigned char asso_values[] =
> > +    {
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> > +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> > +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> > +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86
> > +    };
> > +  unsigned int hval = len;
> > +
> > +  switch (hval)
> > +    {
> > +      default:
> > +        hval += asso_values[static_cast<unsigned char>(str[7])];
> > +      /*FALLTHROUGH*/
> > +      case 7:
> > +        break;
> > +    }
> > +  return hval;
> > +}
> > +
> > +const struct cp_trait *
> > +cp_trait_lookup::find (const char *str, size_t len)
> > +{
> > +  enum
> > +    {
> > +      TOTAL_KEYWORDS = 45,
> > +      MIN_WORD_LENGTH = 7,
> > +      MAX_WORD_LENGTH = 37,
> > +      MIN_HASH_VALUE = 7,
> > +      MAX_HASH_VALUE = 85
> > +    };
> > +
> > +  static const struct cp_trait wordlist[] =
> > +    {
> > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > +      {"__bases", CPTK_BASES, 1, true},
> > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_pod", CPTK_IS_POD, 1, false},
> > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_union", CPTK_IS_UNION, 1, false},
> > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_class", CPTK_IS_CLASS, 1, false},
> > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_same", CPTK_IS_SAME, 2, false},
> > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_final", CPTK_IS_FINAL, 1, false},
> > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > +    };
> > +
> > +  static const signed char lookup[] =
> > +    {
> > +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> > +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > +      -1, 44
> > +    };
> > +
> > +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > +    {
> > +      unsigned int key = hash (str, len);
> > +
> > +      if (key <= MAX_HASH_VALUE)
> > +        {
> > +          int index = lookup[key];
> > +
> > +          if (index >= 0)
> > +            {
> > +              const char *s = wordlist[index].name;
> > +
> > +              if (*str == *s && !strcmp (str + 1, s + 1))
> > +                return &wordlist[index];
> > +            }
> > +        }
> > +    }
> > +  return 0;
> > +}
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index f3abae716fe..432c43400ab 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "contracts.h"
> >  #include "bitmap.h"
> >  #include "builtins.h"
> > +#include "cp-trait.h"
> >
> >
> >  /* The lexer.  */
> > @@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >        /* C++20 extensions.  */
> >      case RID_CONSTINIT:
> >      case RID_CONSTEVAL:
> > -      return true;
> > -
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > +      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
> > +    case RID_TRAIT_TYPE:
> >        return true;
> >
> >      default:
> > @@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
> >  static tree cp_parser_sizeof_operand
> >    (cp_parser *, enum rid);
> >  static cp_expr cp_parser_trait
> > -  (cp_parser *, enum rid);
> > +  (cp_parser *, tree);
> >  static bool cp_parser_declares_only_class_p
> >    (cp_parser *);
> >  static void cp_parser_set_storage_class
> > @@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
> >       case RID_OFFSETOF:
> >         return cp_parser_builtin_offsetof (parser);
> >
> > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > -     case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_EXPR
> > -       return cp_parser_trait (parser, token->keyword);
> > +     case RID_TRAIT_EXPR:
> > +       return cp_parser_trait (parser, token->u.value);
> >
> >       // C++ concepts
> >       case RID_REQUIRES:
> > @@ -11033,28 +11027,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> >  /* Parse a builtin trait expression or type.  */
> >
> >  static cp_expr
> > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > +cp_parser_trait (cp_parser* parser, tree keyword)
> >  {
> > -  cp_trait_kind kind;
> > -  tree type1, type2 = NULL_TREE;
> > -  bool binary = false;
> > -  bool variadic = false;
> > -  bool type = false;
> > +  const char* keyword_str = IDENTIFIER_POINTER (keyword);
> > +  int keyword_len = IDENTIFIER_LENGTH (keyword);
> > +  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
> >
> > -  switch (keyword)
> > -    {
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:                  \
> > -      kind = CPTK_##CODE;             \
> > -      binary = (ARITY == 2);          \
> > -      variadic = (ARITY == -1);               \
> > -      type = (TCC == tcc_type);               \
> > -      break;
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > -    default:
> > -      gcc_unreachable ();
> > -    }
> > +  tree type1, type2 = NULL_TREE;
> > +  bool binary = (trait->arity == 2);
> > +  bool variadic = (trait->arity == -1);
> >
> >    /* Get location of initial token.  */
> >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > @@ -11063,12 +11044,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    cp_lexer_consume_token (parser->lexer);
> >
> >    matching_parens parens;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> >    else
> >      parens.require_open (parser);
> >
> > -  if (kind == CPTK_IS_DEDUCIBLE)
> > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> >      {
> >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> >        type1 = cp_parser_id_expression (parser,
> > @@ -11079,7 +11060,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >                                      /*optional_p=*/false);
> >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> >      }
> > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* __type_pack_element takes an expression as its first argument and uses
> >         template-id syntax instead of function call syntax (for consistency
> >         with Clang).  We special case these properties of __type_pack_element
> > @@ -11094,7 +11075,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    if (type1 == error_mark_node)
> >      return error_mark_node;
> >
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      {
> >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > @@ -11144,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >      }
> >
> >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* cp_parser_enclosed_template_argument_list above already took care
> >         of parsing the closing '>'.  */;
> >    else
> > @@ -11158,17 +11139,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >
> >    /* Complete the trait expression, which may mean either processing
> >       the trait expr now or saving it for template instantiation.  */
> > -  switch (kind)
> > +  switch (trait->kind)
> >      {
> >      case CPTK_BASES:
> >        return cp_expr (finish_bases (type1, false), trait_loc);
> >      case CPTK_DIRECT_BASES:
> >        return cp_expr (finish_bases (type1, true), trait_loc);
> >      default:
> > -      if (type)
> > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > +      if (trait->type)
> > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> >        else
> > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> >      }
> >  }
> >
> > @@ -20081,11 +20062,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> >
> >        return type;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      type = cp_parser_trait (parser, token->keyword);
> > +    case RID_TRAIT_TYPE:
> > +      type = cp_parser_trait (parser, token->u.value);
> >        if (decl_specs)
> >       cp_parser_set_decl_spec_type (decl_specs, type,
> >                                     token,
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 00/39] Optimize type traits performance
  2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
                           ` (38 preceding siblings ...)
  2023-10-10 22:10         ` [PATCH v16 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-11 21:45         ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 01/39] c++: Sort built-in traits alphabetically Ken Matsui
                             ` (39 more replies)
  39 siblings, 40 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v17:

	* Rebased on top of trunk
	* Improved clarity of the commit message
	* Simplified Make-lang.in
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty

Changes in v16:

	* Rebased on top of trunk
	* Improved clarity of the commit message
	* Simplified Make-lang.in and gperf struct
	* Supply -k option to gperf to support older versions than 2.8

Changes in v15:

	* Rebased on top of trunk
	* Use gperf to look up traits instead of enum rid

Changes in v14:

	* Added padding calculation to the commit message

Changes in v13:

	* Fixed ambiguous commit message and comment

Changes in v12:

	* Evaluated all paddings affected by the enum rid change

Changes in v11:

	* Merged all patches into one patch series
	* Rebased on top of trunk
	* Unified commit message style
	* Used _GLIBCXX_USE_BUILTIN_TRAIT

Ken Matsui (39):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits through gperf
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++, libstdc++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++, libstdc++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++, libstdc++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++, libstdc++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc                      |  12 +-
 gcc/c-family/c-common.h                       |   7 +-
 gcc/cp/Make-lang.in                           |  26 ++
 gcc/cp/constraint.cc                          | 112 +++++--
 gcc/cp/cp-objcp-common.cc                     |   6 +-
 gcc/cp/cp-trait-head.in                       |  30 ++
 gcc/cp/cp-trait.def                           |  27 +-
 gcc/cp/cp-trait.gperf                         |  91 ++++++
 gcc/cp/cp-trait.h                             | 285 ++++++++++++++++++
 gcc/cp/lex.cc                                 |   5 +
 gcc/cp/parser.cc                              |  70 ++---
 gcc/cp/semantics.cc                           | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 +++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C          |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_signed.C          |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C             |  48 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C     |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C        |   8 +-
 libstdc++-v3/include/bits/charconv.h          |   2 +-
 libstdc++-v3/include/bits/cpp_type_traits.h   |  18 +-
 libstdc++-v3/include/bits/deque.tcc           |   6 +-
 libstdc++-v3/include/bits/locale_facets.tcc   |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h      |  14 +-
 libstdc++-v3/include/bits/uniform_int_dist.h  |   4 +-
 libstdc++-v3/include/bits/valarray_array.h    |   2 +-
 libstdc++-v3/include/c_global/cmath           |  48 +--
 libstdc++-v3/include/c_std/cmath              |  24 +-
 libstdc++-v3/include/ext/numeric_traits.h     |  18 +-
 libstdc++-v3/include/std/type_traits          | 284 +++++++++++++++--
 libstdc++-v3/include/tr1/cmath                |  24 +-
 45 files changed, 1808 insertions(+), 298 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 01/39] c++: Sort built-in traits alphabetically
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
                             ` (38 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 01/39] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-12 17:02             ` Patrick Palka
  2023-10-11 21:45           ` [PATCH v17 03/39] c++: Implement __is_const built-in trait Ken Matsui
                             ` (37 subsequent siblings)
  39 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

Since RID_MAX soon reaches 255 and all traits are used approximately once in
a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
	and RID_TRAIT_TYPE instead.
	* c-common.h (enum rid): Remove all existing RID values for traits.
	Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.

gcc/cp/ChangeLog:

	* Make-lang.in: Add targets to generate cp-trait.gperf and
	cp-trait.h.
	* cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
	for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
	* parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
	type-yielding traits.  Use RID_TRAIT_TYPE instead.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Likewise, for expression-yielding
	traits.  Use RID_TRAIT_EXPR instead.
	(cp_parser_trait): Look up traits through gperf instead of enum rid.
	* lex.cc (init_reswords): Make ridpointers for RID_TRAIT_EXPR and
	RID_TRAIT_TYPE empty, which do not have corresponding unique
	cannonical spellings.
	* cp-trait-head.in: New file.
	* cp-trait.gperf: New file.
	* cp-trait.h: New file.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |  12 +-
 gcc/c-family/c-common.h   |   7 +-
 gcc/cp/Make-lang.in       |  26 ++++
 gcc/cp/cp-objcp-common.cc |   6 +-
 gcc/cp/cp-trait-head.in   |  30 +++++
 gcc/cp/cp-trait.gperf     |  74 ++++++++++++
 gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
 gcc/cp/lex.cc             |   5 +
 gcc/cp/parser.cc          |  70 ++++-------
 9 files changed, 419 insertions(+), 58 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..f219ccd29e5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
+#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_EXPR,	D_CXXONLY },
 #include "cp/cp-trait.def"
-#undef DEFTRAIT
+#undef DEFTRAIT_EXPR
   /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
+  { "__is_same_as",	RID_TRAIT_EXPR,	D_CXXONLY },
+#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
+  { NAME,		RID_TRAIT_TYPE,	D_CXXONLY },
+#include "cp/cp-trait.def"
+#undef DEFTRAIT_TYPE
 
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..a1a641f4175 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,10 +168,9 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
+  /* C++ traits, defined in cp-trait.def.  */
+  RID_TRAIT_EXPR,
+  RID_TRAIT_TYPE,
 
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2727fb7f8cc..a67d1c3e9f3 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -34,6 +34,8 @@
 # - the compiler proper (eg: cc1plus)
 # - define the names for selecting the language in LANGUAGES.
 
+AWK = @AWK@
+
 # Actual names to use when installing a native compiler.
 CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
 GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,30 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+# We always need the dependency on the .gperf file
+# because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from
+# cp-trait-head.in and cp-trait.def files.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
+	cat $< > $@
+	$(AWK) -F', *' '/^DEFTRAIT_/ { \
+		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+		gsub(/\)/, "", $$3); \
+		print $$2", CPTK_" $$1", "$$3", "type; \
+	}' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..c414d8f5a13 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -434,10 +434,8 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
+    case RID_TRAIT_EXPR:
+    case RID_TRAIT_TYPE:
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
new file mode 100644
index 00000000000..9357eea1238
--- /dev/null
+++ b/gcc/cp/cp-trait-head.in
@@ -0,0 +1,30 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
new file mode 100644
index 00000000000..47e3c1af499
--- /dev/null
+++ b/gcc/cp/cp-trait.gperf
@@ -0,0 +1,74 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
+"__is_abstract", CPTK_IS_ABSTRACT, 1, false
+"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
+"__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_class", CPTK_IS_CLASS, 1, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
+"__is_empty", CPTK_IS_EMPTY, 1, false
+"__is_enum", CPTK_IS_ENUM, 1, false
+"__is_final", CPTK_IS_FINAL, 1, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
+"__is_pod", CPTK_IS_POD, 1, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_same", CPTK_IS_SAME, 2, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
+"__is_trivial", CPTK_IS_TRIVIAL, 1, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_union", CPTK_IS_UNION, 1, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
+"__remove_cv", CPTK_REMOVE_CV, 1, true
+"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
+"__bases", CPTK_BASES, 1, true
+"__direct_bases", CPTK_DIRECT_BASES, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
new file mode 100644
index 00000000000..97ba8492d15
--- /dev/null
+++ b/gcc/cp/cp-trait.h
@@ -0,0 +1,247 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned char asso_values[] =
+    {
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
+       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
+      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
+      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        break;
+    }
+  return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 45,
+      MIN_WORD_LENGTH = 7,
+      MAX_WORD_LENGTH = 37,
+      MIN_HASH_VALUE = 7,
+      MAX_HASH_VALUE = 85
+    };
+
+  static const struct cp_trait wordlist[] =
+    {
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__bases", CPTK_BASES, 1, true},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+    };
+
+  static const signed char lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
+       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..9eeb29adde5 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -260,6 +260,11 @@ init_reswords (void)
 	set_identifier_kind (id, cik_keyword);
     }
 
+  /* RID_TRAIT_EXPR and RID_TRAIT_TYPE do not have
+     corresponding unique canonical spellings.  */
+  ridpointers [(int) RID_TRAIT_EXPR] = nullptr;
+  ridpointers [(int) RID_TRAIT_TYPE] = nullptr;
+
   for (i = 0; i < NUM_INT_N_ENTS; i++)
     {
       char name[50];
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..432c43400ab 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "contracts.h"
 #include "bitmap.h"
 #include "builtins.h"
+#include "cp-trait.h"
 
 \f
 /* The lexer.  */
@@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* C++20 extensions.  */
     case RID_CONSTINIT:
     case RID_CONSTEVAL:
-      return true;
-
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
+      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
+    case RID_TRAIT_TYPE:
       return true;
 
     default:
@@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, tree);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
+	case RID_TRAIT_EXPR:
+	  return cp_parser_trait (parser, token->u.value);
 
 	// C++ concepts
 	case RID_REQUIRES:
@@ -11033,28 +11027,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, tree keyword)
 {
-  cp_trait_kind kind;
-  tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
+  const char* keyword_str = IDENTIFIER_POINTER (keyword);
+  int keyword_len = IDENTIFIER_LENGTH (keyword);
+  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
 
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  tree type1, type2 = NULL_TREE;
+  bool binary = (trait->arity == 2);
+  bool variadic = (trait->arity == -1);
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11044,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11060,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11075,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11139,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,11 +20062,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    case RID_TRAIT_TYPE:
+      type = cp_parser_trait (parser, token->u.value);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 03/39] c++: Implement __is_const built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 01/39] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
                             ` (36 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

	* Make-lang.in: Update key positions for gperf, based on
	automatically computed values.
	* cp-trait.def: Define __is_const.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/Make-lang.in                      |   2 +-
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 202 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_const.C      |  19 +++
 8 files changed, 135 insertions(+), 100 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index a67d1c3e9f3..7479e7dc00b 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -195,7 +195,7 @@ $(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
 else
 $(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
 endif
-	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+	gperf -o -C -E -k '6,8' -D -N 'find' -L C++ \
 		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
 
 # The cp-trait.gperf file itself is generated from
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47e3c1af499..47a5ec9ee6f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
+"__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
 "__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
 "__is_empty", CPTK_IS_EMPTY, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 97ba8492d15..c9005eee1ff 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -1,5 +1,5 @@
 /* C++ code produced by gperf version 3.1 */
-/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+/* Command-line: gperf -o -C -E -k 6,8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 79, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
-       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
-      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
-      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
+      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
+      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -104,6 +104,8 @@ cp_trait_lookup::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
       case 7:
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
         break;
     }
   return hval;
@@ -114,116 +116,118 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 85
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
-       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
-      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
-      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
-      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
+      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
+      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
+      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
+      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 04/39] libstdc++: Optimize is_const trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (2 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 03/39] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
                             ` (35 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 05/39] c++: Implement __is_volatile built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (3 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
                             ` (34 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_volatile.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 ++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/cp-trait.gperf                    |  1 +
 gcc/cp/cp-trait.h                        | 38 +++++++++++++-----------
 gcc/cp/semantics.cc                      |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C   | 19 ++++++++++++
 7 files changed, 51 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47a5ec9ee6f..ea7abda6c75 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index c9005eee1ff..f462794d5db 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
       40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
       96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,27 +125,29 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
@@ -159,9 +161,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -215,19 +217,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
-      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
-      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
-      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
-      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
+      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
+      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 06/39] libstdc++: Optimize is_volatile trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (4 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 07/39] c++: Implement __is_array built-in trait Ken Matsui
                             ` (33 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 07/39] c++: Implement __is_array built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (5 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
                             ` (32 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 148 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_array.C      |  28 +++++
 7 files changed, 116 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ea7abda6c75..fb162cac164 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f462794d5db..526e63dec42 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
-      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
-      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
+       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
+       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,108 +116,110 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 47,
+      TOTAL_KEYWORDS = 48,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -226,10 +228,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
       14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
-      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 47
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 08/39] libstdc++: Optimize is_array trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (6 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 07/39] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                             ` (31 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 09/39] c++: Implement __is_unbounded_array built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (7 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                             ` (30 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unbounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNBOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 42 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 ++++++++++++++++
 7 files changed, 71 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index fb162cac164..a894fc8c74c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 526e63dec42..47060ffbbef 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 48,
+      TOTAL_KEYWORDS = 49,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,30 +125,32 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
@@ -161,9 +163,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -219,21 +221,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
-      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
+      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
+      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 47
+      -1, -1, -1, 48
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 10/39] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (8 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
                             ` (29 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 11/39] c++: Implement __is_bounded_array built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (9 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                             ` (28 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_bounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_BOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |  3 +
 gcc/cp/cp-trait.def                         |  1 +
 gcc/cp/cp-trait.gperf                       |  1 +
 gcc/cp/cp-trait.h                           | 86 +++++++++++----------
 gcc/cp/semantics.cc                         |  4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  3 +
 gcc/testsuite/g++.dg/ext/is_bounded_array.C | 38 +++++++++
 7 files changed, 94 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index a894fc8c74c..90fcdc01de6 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false
 "__is_class", CPTK_IS_CLASS, 1, false
 "__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 47060ffbbef..f22a6e93618 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
        50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
       116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 49,
+      TOTAL_KEYWORDS = 50,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,54 +125,56 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -181,7 +183,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -191,27 +193,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
@@ -219,9 +221,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -230,12 +232,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
-      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
+      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
+      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 48
+      -1, -1, -1, 49
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 12/39] libstdc++: Optimize is_bounded_array trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (10 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                             ` (27 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 13/39] c++: Implement __is_scoped_enum built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (11 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                             ` (26 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scoped_enum.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCOPED_ENUM.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                      |   3 +
 gcc/cp/cp-trait.def                       |   1 +
 gcc/cp/cp-trait.gperf                     |   1 +
 gcc/cp/cp-trait.h                         | 161 +++++++++++-----------
 gcc/cp/semantics.cc                       |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |   3 +
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C |  67 +++++++++
 7 files changed, 160 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90fcdc01de6..f3fd82ba549 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -59,6 +59,7 @@ struct cp_trait {
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f22a6e93618..9c18165eb68 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
-       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
-      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
+      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
+      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
+      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,56 +116,60 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 50,
+      TOTAL_KEYWORDS = 51,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -173,22 +177,18 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
@@ -197,47 +197,48 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
-      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 49
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
+      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
+      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
+      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
+      50
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 14/39] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (12 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
                             ` (25 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 15/39] c++: Implement __is_member_pointer built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (13 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                             ` (24 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_MEMBER_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 153 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_member_pointer.C |  30 ++++
 7 files changed, 120 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index f3fd82ba549..3775b11283d 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 9c18165eb68..dfd60cec6e6 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 111, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
-      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
-      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
-      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
+       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
+       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
+      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118
     };
   unsigned int hval = len;
 
@@ -116,69 +116,67 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 51,
+      TOTAL_KEYWORDS = 52,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 117
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -187,58 +185,63 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
-      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
-      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
-      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
-      50
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
+      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
+      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
+      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
+      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
+      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, 51
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 16/39] libstdc++: Optimize is_member_pointer trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (14 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                             ` (23 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 17/39] c++: Implement __is_member_function_pointer built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (15 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                             ` (22 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_function_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_FUNCTION_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |   3 +
 gcc/cp/cp-trait.def                           |   1 +
 gcc/cp/cp-trait.gperf                         |   1 +
 gcc/cp/cp-trait.h                             | 176 +++++++++---------
 gcc/cp/semantics.cc                           |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |   3 +
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 7 files changed, 131 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 3775b11283d..b28efbab322 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index dfd60cec6e6..d3d4bdf9799 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 111, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
-       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
-       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
-      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
+      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
+      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
+      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -116,132 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 52,
+      TOTAL_KEYWORDS = 53,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 117
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
-      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
-      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
-      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
-      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
-      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, 51
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
+      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 18/39] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (16 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                             ` (21 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 19/39] c++: Implement __is_member_object_pointer built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (17 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                             ` (20 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_object_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_OBJECT_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 +
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 62 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 +
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++
 7 files changed, 74 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index b28efbab322..32199a1fe9a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
+"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index d3d4bdf9799..799fe2b792f 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 53,
+      TOTAL_KEYWORDS = 54,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,57 +125,57 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,25 +185,25 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
@@ -211,12 +211,14 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
@@ -229,7 +231,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -240,8 +242,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
       -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
-      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
+      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 20/39] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (18 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 21/39] c++: Implement __is_reference built-in trait Ken Matsui
                             ` (19 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 21/39] c++: Implement __is_reference built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (19 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
                             ` (18 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_reference.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 113 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_reference.C  |  34 +++++++
 7 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 32199a1fe9a..5989b84727f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 799fe2b792f..f0b4f96d4a9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 94, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
-      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
-      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
-      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
+       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
+       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
+      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   unsigned int hval = len;
 
@@ -116,58 +116,58 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 54,
+      TOTAL_KEYWORDS = 55,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 100
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -175,7 +175,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,7 +185,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -207,15 +207,13 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
@@ -223,6 +221,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,8 +231,10 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false}
     };
 
   static const signed char lookup[] =
@@ -241,9 +243,10 @@ cp_trait_lookup::find (const char *str, size_t len)
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
+      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      -1, -1, 54
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 22/39] libstdc++: Optimize is_reference trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (20 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 21/39] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:45           ` [PATCH v17 23/39] c++: Implement __is_function built-in trait Ken Matsui
                             ` (17 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 23/39] c++: Implement __is_function built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (21 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-11 21:45           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
                             ` (16 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:45 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_function.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 143 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_function.C   |  58 +++++++++
 7 files changed, 143 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5989b84727f..771242a7f45 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -50,6 +50,7 @@ struct cp_trait {
 "__is_empty", CPTK_IS_EMPTY, 1, false
 "__is_enum", CPTK_IS_ENUM, 1, false
 "__is_final", CPTK_IS_FINAL, 1, false
+"__is_function", CPTK_IS_FUNCTION, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f0b4f96d4a9..b6db58e93c9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 94, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
-       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
-       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
-      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
+       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
+       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
+      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,113 +116,113 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 55,
+      TOTAL_KEYWORDS = 56,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 100
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,10 +231,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false}
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
@@ -242,11 +244,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
-      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      -1, -1, 54
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
+      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 55
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 24/39] libstdc++: Optimize is_function trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (22 preceding siblings ...)
  2023-10-11 21:45           ` [PATCH v17 23/39] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 25/39] libstdc++: Optimize is_object " Ken Matsui
                             ` (15 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 25/39] libstdc++: Optimize is_object trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (23 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
                             ` (14 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 26/39] c++: Implement __remove_pointer built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (24 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 25/39] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                             ` (13 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/cp-trait.gperf                     |  1 +
 gcc/cp/cp-trait.h                         | 32 +++++++-------
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 6 files changed, 78 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 771242a7f45..8fbd67788d5 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -77,6 +77,7 @@ struct cp_trait {
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
 "__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_pointer", CPTK_REMOVE_POINTER, 1, true
 "__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
 "__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
 "__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b6db58e93c9..ad2c2a2d250 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 56,
+      TOTAL_KEYWORDS = 57,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,7 +125,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
@@ -137,17 +137,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
@@ -235,21 +237,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
-      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 55
+       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
+      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
+      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
+      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 56
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 27/39] libstdc++: Optimize remove_pointer trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (25 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
                             ` (12 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 28/39] c++, libstdc++: Implement __is_pointer built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (26 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
                             ` (11 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.
	* g++.dg/tm/pr46567.C (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* g++.dg/torture/20070621-1.C: Likewise.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Rename to ...
	(__is_ptr): ... this.
	* include/bits/deque.tcc: Use __is_ptr instead.
	* include/bits/stl_algobase.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 155 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_pointer.C       |  51 +++++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  22 +--
 gcc/testsuite/g++.dg/torture/20070621-1.C   |   4 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   6 +-
 libstdc++-v3/include/bits/deque.tcc         |   6 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   6 +-
 13 files changed, 165 insertions(+), 101 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 8fbd67788d5..5d40e04f91c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
+"__is_pointer", CPTK_IS_POINTER, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ad2c2a2d250..ab783b161c7 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
-       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
-       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
-      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
+       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
+      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
+      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,78 +116,78 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 57,
+      TOTAL_KEYWORDS = 58,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -205,23 +205,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_array", CPTK_IS_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
@@ -236,22 +240,19 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
-      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
       25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
-      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
-      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 56
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
+      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
+      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      57
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 6d791484448..f08bbf6fd7b 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -192,13 +192,13 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -226,7 +226,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
@@ -1202,8 +1202,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
       typedef typename iterator_traits<_II>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueTypeI)
-		      && __is_pointer<_II>::__value
-		      && __is_pointer<_OI>::__value
+		      && __is_ptr<_II>::__value
+		      && __is_ptr<_OI>::__value
 	&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
       return std::__copy_move<_IsMove, __simple,
 		       _Category>::__copy_m(__first, __last, __result);
@@ -1294,8 +1294,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_BI2>::value_type _ValueType2;
       typedef typename iterator_traits<_BI1>::iterator_category _Category;
       const bool __simple = (__is_pod(_ValueType1)
-		      && __is_pointer<_BI1>::__value
-		      && __is_pointer<_BI2>::__value
+		      && __is_ptr<_BI1>::__value
+		      && __is_ptr<_BI2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__copy_move_backward<_IsMove, __simple,
 				_Category>::__copy_move_b(__first,
@@ -1426,8 +1426,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple = (__is_integer<_ValueType1>::__value
-		      && __is_pointer<_II1>::__value
-		      && __is_pointer<_II2>::__value
+		      && __is_ptr<_II1>::__value
+		      && __is_ptr<_II2>::__value
 	&& __are_same<_ValueType1, _ValueType2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1515,8 +1515,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
   && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
   && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
-  && __is_pointer<_II1>::__value
-  && __is_pointer<_II2>::__value);
+  && __is_ptr<_II1>::__value
+  && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
 	   __first2, __last2);
     }
diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C b/gcc/testsuite/g++.dg/torture/20070621-1.C
index d8a6a76b6b0..b05136163e8 100644
--- a/gcc/testsuite/g++.dg/torture/20070621-1.C
+++ b/gcc/testsuite/g++.dg/torture/20070621-1.C
@@ -18,7 +18,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
         enum {
   __value = 0 };
       };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
         enum {
   __value = 0 };
       };
@@ -49,7 +49,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     template<typename _II1, typename _II2>     inline bool     __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2)     {
         typedef typename iterator_traits<_II1>::value_type _ValueType1;
         typedef typename iterator_traits<_II2>::value_type _ValueType2;
-        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_pointer<_II1>::__value                       && __is_pointer<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
+        const bool __simple = (__is_integer<_ValueType1>::__value                       && __is_ptr<_II1>::__value                       && __is_ptr<_II2>::__value         && __are_same<_ValueType1, _ValueType2>::__value);
         return std::__equal<__simple>::equal(__first1, __last1, __first2);
       }
     template<typename _II1, typename _II2>     inline bool     equal(_II1 __first1, _II1 __last1, _II2 __first2)     {
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index 4dbd32bd298..be0689096fb 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -17,7 +17,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_pointer     {
+    template<typename _Tp>     struct __is_ptr     {
 	enum {
 	    __value = 0 };
     };
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..3711e4be526 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -364,14 +364,14 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // Pointer types
   //
   template<typename _Tp>
-    struct __is_pointer
+    struct __is_ptr
     {
       enum { __value = 0 };
       typedef __false_type __type;
     };
 
   template<typename _Tp>
-    struct __is_pointer<_Tp*>
+    struct __is_ptr<_Tp*>
     {
       enum { __value = 1 };
       typedef __true_type __type;
@@ -390,7 +390,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
+    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc
index a212b8a6940..08d888ee8af 100644
--- a/libstdc++-v3/include/bits/deque.tcc
+++ b/libstdc++-v3/include/bits/deque.tcc
@@ -1273,7 +1273,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr>::__value
+	 && __is_ptr<_Ptr>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
@@ -1329,8 +1329,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       const bool __simple =
 	(__is_memcmp_ordered_with<_Tp1, _Tp2>::__value
-	 && __is_pointer<_Ptr1>::__value
-	 && __is_pointer<_Ptr2>::__value
+	 && __is_ptr<_Ptr1>::__value
+	 && __is_ptr<_Ptr2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 2f5a4bd4fd4..d1438429487 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1217,7 +1217,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     {
       typedef typename iterator_traits<_II1>::value_type _ValueType1;
       const bool __simple = ((__is_integer<_ValueType1>::__value
-			      || __is_pointer<_ValueType1>::__value)
+			      || __is_ptr<_ValueType1>::__value)
 			     && __memcmpable<_II1, _II2>::__value);
       return std::__equal<__simple>::equal(__first1, __last1, __first2);
     }
@@ -1380,8 +1380,8 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
 	(__is_memcmp_ordered_with<_ValueType1, _ValueType2>::__value
-	 && __is_pointer<_II1>::__value
-	 && __is_pointer<_II2>::__value
+	 && __is_ptr<_II1>::__value
+	 && __is_ptr<_II2>::__value
 #if __cplusplus > 201703L && __cpp_lib_concepts
 	 // For C++20 iterator_traits<volatile T*>::value_type is non-volatile
 	 // so __is_byte<T> could be true, but we can't use memcmp with
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 29/39] libstdc++: Optimize is_pointer trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (27 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
                             ` (10 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_ptr): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 3711e4be526..4da1e7c407c 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_ptr : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_ptr
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (28 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                             ` (9 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_arithmetic.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.
	* g++.dg/tm/pr46567.C (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_arithmetic): Rename to ...
	(__is_arith): ... this.
	* include/c_global/cmath: Use __is_arith instead.
	* include/c_std/cmath: Likewise.
	* include/tr1/cmath: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 184 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_arithmetic.C    |  33 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |   6 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   4 +-
 libstdc++-v3/include/c_global/cmath         |  48 ++---
 libstdc++-v3/include/c_std/cmath            |  24 +--
 libstdc++-v3/include/tr1/cmath              |  24 +--
 13 files changed, 193 insertions(+), 146 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5d40e04f91c..9050c36f105 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ab783b161c7..31fd5075f2d 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 97, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
-       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
-      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
-      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
+        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
+       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
+      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104
     };
   unsigned int hval = len;
 
@@ -116,130 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 58,
+      TOTAL_KEYWORDS = 59,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 103
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
@@ -247,12 +249,12 @@ cp_trait_lookup::find (const char *str, size_t len)
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
-      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      57
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
+      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
+      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
+      -1, -1, 57, -1, -1, 58
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index f08bbf6fd7b..79d304e0309 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -217,16 +217,16 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef __true_type __type;
     };
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
   template<typename _Tp>
     struct __is_fundamental
-    : public __traitor<__is_void<_Tp>, __is_arithmetic<_Tp> >
+    : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
     struct __is_char
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index be0689096fb..da592b9fd23 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -25,9 +25,9 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
 	enum {
 	    __value = 0 };
     };
-    template<typename _Tp>     struct __is_arithmetic     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
+    template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4da1e7c407c..51ed5b07716 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -389,7 +389,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // An arithmetic type is an integer type or a floating point type
   //
   template<typename _Tp>
-    struct __is_arithmetic
+    struct __is_arith
     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >
     { };
 
@@ -398,7 +398,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // 
   template<typename _Tp>
     struct __is_scalar
-    : public __traitor<__is_arithmetic<_Tp>, __is_ptr<_Tp> >
+    : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
   //
diff --git a/libstdc++-v3/include/c_global/cmath b/libstdc++-v3/include/c_global/cmath
index 6461c92ebfe..a0ddc1dbbeb 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -1259,8 +1259,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1285,8 +1285,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isgreaterequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1311,8 +1311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isless(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1337,8 +1337,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessequal(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1363,8 +1363,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     islessgreater(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1389,8 +1389,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT
   template<typename _Tp, typename _Up>
     constexpr typename
-    __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value
-			    && __is_arithmetic<_Up>::__value), bool>::__type
+    __gnu_cxx::__enable_if<(__is_arith<_Tp>::__value
+			    && __is_arith<_Up>::__value), bool>::__type
     isunordered(_Tp __x, _Up __y)
     {
       typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type;
@@ -1401,7 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #else
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -1411,7 +1411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -1420,7 +1420,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -1429,7 +1429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -1438,7 +1438,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -1447,7 +1447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -1456,7 +1456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -1465,7 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -1474,7 +1474,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -1483,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -1492,7 +1492,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -1501,7 +1501,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/c_std/cmath b/libstdc++-v3/include/c_std/cmath
index 588ee1e6dc4..c1db699ecdb 100644
--- a/libstdc++-v3/include/c_std/cmath
+++ b/libstdc++-v3/include/c_std/cmath
@@ -467,7 +467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #undef isunordered
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -477,7 +477,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -486,7 +486,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -495,7 +495,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -504,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -513,7 +513,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -522,7 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -531,7 +531,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -540,7 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -549,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, 
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -558,7 +558,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -567,7 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
diff --git a/libstdc++-v3/include/tr1/cmath b/libstdc++-v3/include/tr1/cmath
index ba1b60cc945..2e80f1d0d00 100644
--- a/libstdc++-v3/include/tr1/cmath
+++ b/libstdc++-v3/include/tr1/cmath
@@ -307,7 +307,7 @@ namespace tr1
 
   /// Function template definitions [8.16.3].
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     fpclassify(_Tp __f)
     {
@@ -317,7 +317,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isfinite(_Tp __f)
     {
@@ -326,7 +326,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isinf(_Tp __f)
     {
@@ -335,7 +335,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnan(_Tp __f)
     {
@@ -344,7 +344,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isnormal(_Tp __f)
     {
@@ -353,7 +353,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     signbit(_Tp __f)
     {
@@ -362,7 +362,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreater(_Tp __f1, _Tp __f2)
     {
@@ -371,7 +371,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isgreaterequal(_Tp __f1, _Tp __f2)
     {
@@ -380,7 +380,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isless(_Tp __f1, _Tp __f2)
     {
@@ -389,7 +389,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessequal(_Tp __f1, _Tp __f2)
     {
@@ -398,7 +398,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     islessgreater(_Tp __f1, _Tp __f2)
     {
@@ -407,7 +407,7 @@ namespace tr1
     }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value,
+    inline typename __gnu_cxx::__enable_if<__is_arith<_Tp>::__value,
 					   int>::__type
     isunordered(_Tp __f1, _Tp __f2)
     {
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 31/39] libstdc++: Optimize is_arithmetic trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (29 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
                             ` (8 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 32/39] libstdc++: Optimize is_fundamental trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (30 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 33/39] libstdc++: Optimize is_compound " Ken Matsui
                             ` (7 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 33/39] libstdc++: Optimize is_compound trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (31 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
                             ` (6 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 34/39] c++: Implement __is_unsigned built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (32 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 33/39] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                             ` (5 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unsigned.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNSIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 118 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_unsigned.C   |  47 +++++++++
 7 files changed, 120 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 9050c36f105..90d05bca5c1 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -74,6 +74,7 @@ struct cp_trait {
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_unsigned", CPTK_IS_UNSIGNED, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 31fd5075f2d..75ab2b5edfa 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 97, duplicates = 0 */
+/* maximum key range = 129, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
-        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
-       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
-      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
+       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
+       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
+      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136
     };
   unsigned int hval = len;
 
@@ -116,46 +116,44 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 59,
+      TOTAL_KEYWORDS = 60,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 103
+      MAX_HASH_VALUE = 135
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
@@ -165,11 +163,11 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -180,7 +178,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
 #line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -207,6 +205,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
@@ -223,8 +223,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 70 "../../gcc/cp/cp-trait.gperf"
@@ -242,19 +242,23 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
-      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
-      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
+       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
+      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
       -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58
+      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 35/39] libstdc++: Optimize is_unsigned trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (33 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
                             ` (4 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 36/39] c++, libstdc++: Implement __is_signed built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (34 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
                             ` (3 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_signed.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

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

libstdc++-v3/ChangeLog:

	* include/ext/numeric_traits.h (__is_signed): Rename to ...
	(__is_signed_type): ... this.
	* include/bits/charconv.h: Use __is_signed_type instead.
	* include/bits/locale_facets.tcc: Likewise.
	* include/bits/uniform_int_dist.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 211 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_signed.C         |  47 +++++
 gcc/testsuite/g++.dg/tm/pr46567.C            |  12 +-
 libstdc++-v3/include/bits/charconv.h         |   2 +-
 libstdc++-v3/include/bits/locale_facets.tcc  |   6 +-
 libstdc++-v3/include/bits/uniform_int_dist.h |   4 +-
 libstdc++-v3/include/ext/numeric_traits.h    |  18 +-
 12 files changed, 186 insertions(+), 126 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90d05bca5c1..de0ba162e7a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 75ab2b5edfa..6d1078de2fe 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 129, duplicates = 0 */
+/* maximum key range = 119, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
-       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
-       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
-      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
+       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
+       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
+      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126
     };
   unsigned int hval = len;
 
@@ -116,149 +116,150 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 60,
+      TOTAL_KEYWORDS = 61,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 135
+      MAX_HASH_VALUE = 125
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_signed", CPTK_IS_SIGNED, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 36 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 37 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
-      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
+       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
+      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
+      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
+      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
+      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index 79d304e0309..c891aff20f4 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -403,7 +403,7 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
     {
       static const _Value __min = (((_Value)(-1) < 0) ? (_Value)1 << (sizeof(_Value) * 8 - ((_Value)(-1) < 0)) : (_Value)0);
       static const _Value __max = (((_Value)(-1) < 0) ? (((((_Value)1 << ((sizeof(_Value) * 8 - ((_Value)(-1) < 0)) - 1)) - 1) << 1) + 1) : ~(_Value)0);
-      static const bool __is_signed = ((_Value)(-1) < 0);
+      static const bool __is_signed_type = ((_Value)(-1) < 0);
       static const int __digits = (sizeof(_Value) * 8 - ((_Value)(-1) < 0));
     };
   template<typename _Value>
@@ -411,21 +411,21 @@ namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
   template<typename _Value>
     const _Value __numeric_traits_integer<_Value>::__max;
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
   template<typename _Value>
     struct __numeric_traits_floating
     {
       static const int __max_digits10 = (2 + (std::__are_same<_Value, float>::__value ? 24 : std::__are_same<_Value, double>::__value ? 53 : 64) * 3010 / 10000);
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = (std::__are_same<_Value, float>::__value ? 6 : std::__are_same<_Value, double>::__value ? 15 : 18);
       static const int __max_exponent10 = (std::__are_same<_Value, float>::__value ? 38 : std::__are_same<_Value, double>::__value ? 308 : 4932);
     };
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__max_digits10;
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
   template<typename _Value>
@@ -1513,8 +1513,8 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
       typedef typename iterator_traits<_II2>::value_type _ValueType2;
       const bool __simple =
  (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value
-  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed
-  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed
+  && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed_type
+  && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed_type
   && __is_ptr<_II1>::__value
   && __is_ptr<_II2>::__value);
       return std::__lexicographical_compare<__simple>::__lc(__first1, __last1,
diff --git a/libstdc++-v3/include/bits/charconv.h b/libstdc++-v3/include/bits/charconv.h
index 20da8303f7a..1acf1e46e4c 100644
--- a/libstdc++-v3/include/bits/charconv.h
+++ b/libstdc++-v3/include/bits/charconv.h
@@ -46,7 +46,7 @@ namespace __detail
   // This accepts 128-bit integers even in strict mode.
   template<typename _Tp>
     constexpr bool __integer_to_chars_is_unsigned
-      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed;
+      = ! __gnu_cxx::__int_traits<_Tp>::__is_signed_type;
 #endif
 
   // Generic implementation for arbitrary bases.
diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc
index 6bfff7d6289..38a6920abe9 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -470,7 +470,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	bool __testfail = false;
 	bool __testoverflow = false;
 	const __unsigned_type __max =
-	  (__negative && __num_traits::__is_signed)
+	  (__negative && __num_traits::__is_signed_type)
 	  ? -static_cast<__unsigned_type>(__num_traits::__min)
 	  : __num_traits::__max;
 	const __unsigned_type __smax = __max / __base;
@@ -573,7 +573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	  }
 	else if (__testoverflow)
 	  {
-	    if (__negative && __num_traits::__is_signed)
+	    if (__negative && __num_traits::__is_signed_type)
 	      __v = __num_traits::__min;
 	    else
 	      __v = __num_traits::__max;
@@ -914,7 +914,7 @@ _GLIBCXX_BEGIN_NAMESPACE_LDBL
 	    if (__v >= 0)
 	      {
 		if (bool(__flags & ios_base::showpos)
-		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed)
+		    && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed_type)
 		  *--__cs = __lit[__num_base::_S_oplus], ++__len;
 	      }
 	    else
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h
index 7ccf930a6d4..73b808e57f3 100644
--- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -258,8 +258,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	{
 	  using _Up_traits = __gnu_cxx::__int_traits<_Up>;
 	  using _Wp_traits = __gnu_cxx::__int_traits<_Wp>;
-	  static_assert(!_Up_traits::__is_signed, "U must be unsigned");
-	  static_assert(!_Wp_traits::__is_signed, "W must be unsigned");
+	  static_assert(!_Up_traits::__is_signed_type, "U must be unsigned");
+	  static_assert(!_Wp_traits::__is_signed_type, "W must be unsigned");
 	  static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),
 			"W must be twice as wide as U");
 
diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h
index dcbc2d12927..c618f211775 100644
--- a/libstdc++-v3/include/ext/numeric_traits.h
+++ b/libstdc++-v3/include/ext/numeric_traits.h
@@ -67,15 +67,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       // NB: these two are also available in std::numeric_limits as compile
       // time constants, but <limits> is big and we can avoid including it.
-      static const bool __is_signed = (_Value)(-1) < 0;
+      static const bool __is_signed_type = (_Value)(-1) < 0;
       static const int __digits
-	= __is_integer_nonstrict<_Value>::__width - __is_signed;
+	= __is_integer_nonstrict<_Value>::__width - __is_signed_type;
 
       // The initializers must be constants so that __max and __min are too.
-      static const _Value __max = __is_signed
+      static const _Value __max = __is_signed_type
 	? (((((_Value)1 << (__digits - 1)) - 1) << 1) + 1)
 	: ~(_Value)0;
-      static const _Value __min = __is_signed ? -__max - 1 : (_Value)0;
+      static const _Value __min = __is_signed_type ? -__max - 1 : (_Value)0;
     };
 
   template<typename _Value>
@@ -85,7 +85,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const _Value __numeric_traits_integer<_Value>::__max;
 
   template<typename _Value>
-    const bool __numeric_traits_integer<_Value>::__is_signed;
+    const bool __numeric_traits_integer<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_integer<_Value>::__digits;
@@ -161,7 +161,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static const int __max_digits10 = __glibcxx_max_digits10(_Value);
 
       // See above comment...
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = __glibcxx_digits10(_Value);
       static const int __max_exponent10 = __glibcxx_max_exponent10(_Value);
     };
@@ -170,7 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     const int __numeric_traits_floating<_Value>::__max_digits10;
 
   template<typename _Value>
-    const bool __numeric_traits_floating<_Value>::__is_signed;
+    const bool __numeric_traits_floating<_Value>::__is_signed_type;
 
   template<typename _Value>
     const int __numeric_traits_floating<_Value>::__digits10;
@@ -210,7 +210,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ibm128>
     {
       static const int __max_digits10 = 33;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 31;
       static const int __max_exponent10 = 308;
     };
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __numeric_traits_floating<__ieee128>
     {
       static const int __max_digits10 = 36;
-      static const bool __is_signed = true;
+      static const bool __is_signed_type = true;
       static const int __digits10 = 33;
       static const int __max_exponent10 = 4932;
     };
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 37/39] libstdc++: Optimize is_signed trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (35 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
                             ` (2 subsequent siblings)
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 38/39] c++, libstdc++: Implement __is_scalar built-in trait
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (36 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-11 21:46           ` [PATCH v17 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar. The existent
__is_scalar codes were replaced with __is_scalar_type to avoid unintentional
macro replacement by the new built-in.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scalar.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCALAR.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.
	* g++.dg/tm/pr46567.C: Use __is_scalar_type instead.
	* g++.dg/torture/pr57107.C: Likewise.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_scalar): Rename to ...
	(__is_scalar_type): ... this.
	* include/bits/stl_algobase.h: Use __is_scalar_type instead.
	* include/bits/valarray_array.h: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |   3 +
 gcc/cp/cp-trait.def                         |   1 +
 gcc/cp/cp-trait.gperf                       |   1 +
 gcc/cp/cp-trait.h                           | 186 ++++++++++----------
 gcc/cp/semantics.cc                         |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |   3 +
 gcc/testsuite/g++.dg/ext/is_scalar.C        |  31 ++++
 gcc/testsuite/g++.dg/tm/pr46567.C           |  10 +-
 gcc/testsuite/g++.dg/torture/pr57107.C      |   4 +-
 libstdc++-v3/include/bits/cpp_type_traits.h |   2 +-
 libstdc++-v3/include/bits/stl_algobase.h    |   8 +-
 libstdc++-v3/include/bits/valarray_array.h  |   2 +-
 12 files changed, 150 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index de0ba162e7a..ef51c713c58 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scalar", CPTK_IS_SCALAR, 1, false
 "__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 6d1078de2fe..8c68af420f9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -78,10 +78,10 @@ cp_trait_lookup::hash (const char *str, size_t len)
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
-       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
-       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
-      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  40, 126,  25,  21,  50,
+        0,   0,  30,  10, 126,   0, 126, 126,  25,   5,
+       50,   0,  61, 126,  10,  10,   5,   0,  15, 126,
+      126,   5, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 61,
+      TOTAL_KEYWORDS = 62,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,141 +125,143 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 89 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_signed", CPTK_IS_SIGNED, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 33 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 32 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scalar", CPTK_IS_SCALAR, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
-      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
-      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
-      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
-      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5,  6,  7,  8,  9, -1, -1, -1, 10, 11, -1, 12, 13,
+      14, 15, 16, 17, -1, 18, -1, 19, 20, 21, 22, 23, 24, 25,
+      26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
+      -1, -1, 38, -1, 39, -1, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, 45, -1, 46, 47, 48, -1, -1, 49, 50, 51, 52, -1, -1,
+      -1, 53, -1, -1, -1, -1, 54, -1, -1, 55, -1, -1, -1, -1,
+      56, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, 58, -1,
+      -1, -1, -1, -1, 59, -1, 60, -1, -1, -1, -1, -1, -1, 61
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
diff --git a/gcc/testsuite/g++.dg/tm/pr46567.C b/gcc/testsuite/g++.dg/tm/pr46567.C
index c891aff20f4..393f936ea72 100644
--- a/gcc/testsuite/g++.dg/tm/pr46567.C
+++ b/gcc/testsuite/g++.dg/tm/pr46567.C
@@ -225,7 +225,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     : public __traitor<__is_void<_Tp>, __is_arith<_Tp> >
     { };
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
   template<typename _Tp>
@@ -1325,7 +1325,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
        const _Tp& __value)
     {
@@ -1334,7 +1334,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _ForwardIterator, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a(_ForwardIterator __first, _ForwardIterator __last,
       const _Tp& __value)
     {
@@ -1362,7 +1362,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, ++__first)
@@ -1371,7 +1371,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     }
   template<typename _OutputIterator, typename _Size, typename _Tp>
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/gcc/testsuite/g++.dg/torture/pr57107.C b/gcc/testsuite/g++.dg/torture/pr57107.C
index da592b9fd23..4d2ef002e08 100644
--- a/gcc/testsuite/g++.dg/torture/pr57107.C
+++ b/gcc/testsuite/g++.dg/torture/pr57107.C
@@ -27,7 +27,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Tp>     struct __is_arith     : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> >     {
     };
-    template<typename _Tp>     struct __is_scalar     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
+    template<typename _Tp>     struct __is_scalar_type     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >     {
     };
 }
 namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) {
@@ -54,7 +54,7 @@ namespace std __attribute__ ((__visibility__ ("default"))) {
     };
     template<typename _Iterator>     inline typename _Niter_base<_Iterator>::iterator_type     __niter_base(_Iterator __it)     {
     }
-    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
+    template<typename _OutputIterator, typename _Size, typename _Tp>     inline typename     __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type     __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)     {
 	for (__decltype(__n + 0) __niter = __n;
 	     __niter > 0;
 	     --__niter, ++__first)  *__first = __value;
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 51ed5b07716..16980f5b356 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -397,7 +397,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   // A scalar type is an arithmetic type or a pointer type
   // 
   template<typename _Tp>
-    struct __is_scalar
+    struct __is_scalar_type
     : public __traitor<__is_arith<_Tp>, __is_ptr<_Tp> >
     { };
 
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d1438429487..4e334da0832 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -914,7 +914,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -925,7 +925,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _ForwardIterator, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, void>::__type
     __fill_a1(_ForwardIterator __first, _ForwardIterator __last,
 	      const _Tp& __value)
     {
@@ -1063,7 +1063,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<!__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       for (; __n > 0; --__n, (void) ++__first)
@@ -1074,7 +1074,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
   template<typename _OutputIterator, typename _Size, typename _Tp>
     _GLIBCXX20_CONSTEXPR
     inline typename
-    __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
+    __gnu_cxx::__enable_if<__is_scalar_type<_Tp>::__value, _OutputIterator>::__type
     __fill_n_a1(_OutputIterator __first, _Size __n, const _Tp& __value)
     {
       const _Tp __tmp = __value;
diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h
index 222fd5fd900..558817329ce 100644
--- a/libstdc++-v3/include/bits/valarray_array.h
+++ b/libstdc++-v3/include/bits/valarray_array.h
@@ -90,7 +90,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     __valarray_default_construct(_Tp* __b, _Tp* __e)
     {
-      _Array_default_ctor<_Tp, __is_scalar<_Tp>::__value>::_S_do_it(__b, __e);
+      _Array_default_ctor<_Tp, __is_scalar_type<_Tp>::__value>::_S_do_it(__b, __e);
     }
 
   // Turn a raw-memory into an array of _Tp filled with __t
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v17 39/39] libstdc++: Optimize is_scalar trait performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (37 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-11 21:46           ` Ken Matsui
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
  39 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-11 21:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf
  2023-10-11 21:45           ` [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-12 17:02             ` Patrick Palka
  0 siblings, 0 replies; 623+ messages in thread
From: Patrick Palka @ 2023-10-12 17:02 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, jason

On Wed, 11 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all traits are used approximately once in
> a C++ translation unit, this patch instead uses only RID_TRAIT_EXPR and
> RID_TRAIT_TYPE for all traits and uses gperf to look up the specific trait.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Map all traits to RID_TRAIT_EXPR
> 	and RID_TRAIT_TYPE instead.
> 	* c-common.h (enum rid): Remove all existing RID values for traits.
> 	Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 
> gcc/cp/ChangeLog:
> 
> 	* Make-lang.in: Add targets to generate cp-trait.gperf and
> 	cp-trait.h.
> 	* cp-objcp-common.cc (names_builtin_p): Remove all existing RID values
> 	for traits.  Use RID_TRAIT_EXPR and RID_TRAIT_TYPE instead.
> 	* parser.cc (cp_keyword_starts_decl_specifier_p): Likewise, for
> 	type-yielding traits.  Use RID_TRAIT_TYPE instead.
> 	(cp_parser_simple_type_specifier): Likewise.
> 	(cp_parser_primary_expression): Likewise, for expression-yielding
> 	traits.  Use RID_TRAIT_EXPR instead.
> 	(cp_parser_trait): Look up traits through gperf instead of enum rid.
> 	* lex.cc (init_reswords): Make ridpointers for RID_TRAIT_EXPR and
> 	RID_TRAIT_TYPE empty, which do not have corresponding unique
> 	cannonical spellings.
> 	* cp-trait-head.in: New file.
> 	* cp-trait.gperf: New file.
> 	* cp-trait.h: New file.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |  12 +-
>  gcc/c-family/c-common.h   |   7 +-
>  gcc/cp/Make-lang.in       |  26 ++++
>  gcc/cp/cp-objcp-common.cc |   6 +-
>  gcc/cp/cp-trait-head.in   |  30 +++++
>  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
>  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
>  gcc/cp/lex.cc             |   5 +
>  gcc/cp/parser.cc          |  70 ++++-------
>  9 files changed, 419 insertions(+), 58 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..f219ccd29e5 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,12 +508,16 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",		RID_WCHAR,	D_CXXONLY },
>    { "while",		RID_WHILE,	0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,		RID_##CODE,	D_CXXONLY },
> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> +  { NAME,		RID_TRAIT_EXPR,	D_CXXONLY },
>  #include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +#undef DEFTRAIT_EXPR
>    /* An alias for __is_same.  */
> -  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
> +  { "__is_same_as",	RID_TRAIT_EXPR,	D_CXXONLY },
> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> +  { NAME,		RID_TRAIT_TYPE,	D_CXXONLY },
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT_TYPE
>  
>    /* C++ transactional memory.  */
>    { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..a1a641f4175 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,10 +168,9 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> +  /* C++ traits, defined in cp-trait.def.  */
> +  RID_TRAIT_EXPR,
> +  RID_TRAIT_TYPE,
>  
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..a67d1c3e9f3 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
>  # - the compiler proper (eg: cc1plus)
>  # - define the names for selecting the language in LANGUAGES.
>  
> +AWK = @AWK@
> +
>  # Actual names to use when installing a native compiler.
>  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
>  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,30 @@ endif
>  # This is the file that depends on the generated header file.
>  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>  
> +# We always need the dependency on the .gperf file
> +# because it itself is generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> +	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> +		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf file itself is generated from
> +# cp-trait-head.in and cp-trait.def files.
> +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> +	cat $< > $@
> +	$(AWK) -F', *' '/^DEFTRAIT_/ { \
> +		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> +		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> +		gsub(/\)/, "", $$3); \
> +		print $$2", CPTK_" $$1", "$$3", "type; \
> +	}' $(srcdir)/cp/cp-trait.def >> $@
> +
> +# This is the file that depends on the generated header file.
> +cp/parser.o: $(srcdir)/cp/cp-trait.h
> +
>  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
>  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..c414d8f5a13 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -434,10 +434,8 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> +    case RID_TRAIT_EXPR:
> +    case RID_TRAIT_TYPE:
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> new file mode 100644
> index 00000000000..9357eea1238
> --- /dev/null
> +++ b/gcc/cp/cp-trait-head.in
> @@ -0,0 +1,30 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> new file mode 100644
> index 00000000000..47e3c1af499
> --- /dev/null
> +++ b/gcc/cp/cp-trait.gperf
> @@ -0,0 +1,74 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> +"__is_class", CPTK_IS_CLASS, 1, false
> +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> +"__is_empty", CPTK_IS_EMPTY, 1, false
> +"__is_enum", CPTK_IS_ENUM, 1, false
> +"__is_final", CPTK_IS_FINAL, 1, false
> +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> +"__is_pod", CPTK_IS_POD, 1, false
> +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> +"__is_same", CPTK_IS_SAME, 2, false
> +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> +"__is_union", CPTK_IS_UNION, 1, false
> +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> +"__remove_cv", CPTK_REMOVE_CV, 1, true
> +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> +"__bases", CPTK_BASES, 1, true
> +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> new file mode 100644
> index 00000000000..97ba8492d15
> --- /dev/null
> +++ b/gcc/cp/cp-trait.h
> @@ -0,0 +1,247 @@
> +/* C++ code produced by gperf version 3.1 */
> +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> +
> +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> +/* The character set is not based on ISO-646.  */
> +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> +#endif
> +
> +#line 4 "../../gcc/cp/cp-trait.gperf"
> +
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +#line 23 "../../gcc/cp/cp-trait.gperf"
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +/* maximum key range = 79, duplicates = 0 */
> +
> +class cp_trait_lookup
> +{
> +private:
> +  static inline unsigned int hash (const char *str, size_t len);
> +public:
> +  static const struct cp_trait *find (const char *str, size_t len);
> +};
> +
> +inline unsigned int
> +cp_trait_lookup::hash (const char *str, size_t len)
> +{
> +  static const unsigned char asso_values[] =
> +    {
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86
> +    };
> +  unsigned int hval = len;
> +
> +  switch (hval)
> +    {
> +      default:
> +        hval += asso_values[static_cast<unsigned char>(str[7])];
> +      /*FALLTHROUGH*/
> +      case 7:
> +        break;
> +    }
> +  return hval;
> +}
> +
> +const struct cp_trait *
> +cp_trait_lookup::find (const char *str, size_t len)
> +{
> +  enum
> +    {
> +      TOTAL_KEYWORDS = 45,
> +      MIN_WORD_LENGTH = 7,
> +      MAX_WORD_LENGTH = 37,
> +      MIN_HASH_VALUE = 7,
> +      MAX_HASH_VALUE = 85
> +    };
> +
> +  static const struct cp_trait wordlist[] =
> +    {
> +#line 73 "../../gcc/cp/cp-trait.gperf"
> +      {"__bases", CPTK_BASES, 1, true},
> +#line 56 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pod", CPTK_IS_POD, 1, false},
> +#line 48 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> +#line 64 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_union", CPTK_IS_UNION, 1, false},
> +#line 44 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_class", CPTK_IS_CLASS, 1, false},
> +#line 60 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> +#line 41 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> +#line 72 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> +#line 43 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> +#line 40 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> +#line 58 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same", CPTK_IS_SAME, 2, false},
> +#line 42 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> +#line 59 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> +#line 30 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> +#line 63 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> +#line 39 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> +#line 61 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> +#line 57 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> +#line 71 "../../gcc/cp/cp-trait.gperf"
> +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> +#line 62 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> +#line 74 "../../gcc/cp/cp-trait.gperf"
> +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> +#line 51 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> +#line 33 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> +#line 31 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> +#line 55 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> +#line 52 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> +#line 54 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> +#line 32 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> +#line 53 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> +#line 50 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> +#line 67 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> +#line 36 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> +#line 68 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> +#line 34 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> +#line 69 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> +#line 37 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> +#line 35 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> +#line 49 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_final", CPTK_IS_FINAL, 1, false},
> +#line 47 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> +#line 46 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> +#line 45 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> +#line 66 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> +#line 65 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> +#line 70 "../../gcc/cp/cp-trait.gperf"
> +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> +#line 38 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> +    };
> +
> +  static const signed char lookup[] =
> +    {
> +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> +      -1, 44
> +    };
> +
> +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> +    {
> +      unsigned int key = hash (str, len);
> +
> +      if (key <= MAX_HASH_VALUE)
> +        {
> +          int index = lookup[key];
> +
> +          if (index >= 0)
> +            {
> +              const char *s = wordlist[index].name;
> +
> +              if (*str == *s && !strcmp (str + 1, s + 1))
> +                return &wordlist[index];
> +            }
> +        }
> +    }
> +  return 0;
> +}
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..9eeb29adde5 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -260,6 +260,11 @@ init_reswords (void)
>  	set_identifier_kind (id, cik_keyword);
>      }
>  
> +  /* RID_TRAIT_EXPR and RID_TRAIT_TYPE do not have
> +     corresponding unique canonical spellings.  */
> +  ridpointers [(int) RID_TRAIT_EXPR] = nullptr;
> +  ridpointers [(int) RID_TRAIT_TYPE] = nullptr;

Thanks!  This gets the job done, but perhaps it suggests that treating
these identifiers as keywords, and having them share the same rid code,
isn't quite the best approach... really we'd want these identifiers to
be classified as "conditional" keywords that are only treated as actual
keywords whenever they're followed by a '(' (since the only thing you
can do with a built-in trait is to call it) and are otherwise treated as
ordinary identifiers in other contexts.  This way existing uses of these
names in e.g. libstdc++ will continue to be accepted, and won't need to
be renamed.  And we might as well implement this as part of this patch,
since it'd replace the RID_TRAIT_EXPR / RID_TRAIT_TYPE approach.

So I think we should:

  * get rid of RID_TRAIT_EXPR / RID_TRAIT_TYPE
  * add a new 'cik_trait' kind to cp_identifier_kind.  Actually
    let's replace the unused cik_reserved_for_udlit with cik_trait,
    since we currently can't handle more than 7 kinds (we use 3 bits
    to encode cp_identifier_kind within the flags of an IDENTIFIER node)
  * set each built-in trait's identifier kind to cik_trait rather than
    to cik_keyword (in init_reswords or around there)
  * within the parser, replace existing RID_TRAIT_EXPR and RID_TRAIT_TYPE
    checks to instead check for a CPP_NAME token having a cik_trait identifier
    (for an expression- or type-yielding trait as appropriate)
  * In a follow-up patch, we can then refine these checks to additionally
    require that the subsequent token in the token stream is '(' (or '<'
    for the special __type_pack_element built-in trait)

This last step will allow us to accept code like 'int __remove_cv = 42;" :D

> +
>    for (i = 0; i < NUM_INT_N_ENTS; i++)
>      {
>        char name[50];
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index f3abae716fe..432c43400ab 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "contracts.h"
>  #include "bitmap.h"
>  #include "builtins.h"
> +#include "cp-trait.h"
>  
>  \f
>  /* The lexer.  */
> @@ -1165,12 +1166,8 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>        /* C++20 extensions.  */
>      case RID_CONSTINIT:
>      case RID_CONSTEVAL:
> -      return true;
> -
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> +      /* C++ type-yielding built-in traits, defined in cp-trait.def.  */
> +    case RID_TRAIT_TYPE:
>        return true;
>  
>      default:
> @@ -2854,7 +2851,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, tree);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6021,11 +6018,8 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_OFFSETOF:
>  	  return cp_parser_builtin_offsetof (parser);
>  
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -	case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -	  return cp_parser_trait (parser, token->keyword);
> +	case RID_TRAIT_EXPR:
> +	  return cp_parser_trait (parser, token->u.value);
>  
>  	// C++ concepts
>  	case RID_REQUIRES:
> @@ -11033,28 +11027,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>  
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, tree keyword)
>  {
> -  cp_trait_kind kind;
> -  tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> +  const char* keyword_str = IDENTIFIER_POINTER (keyword);
> +  int keyword_len = IDENTIFIER_LENGTH (keyword);
> +  const cp_trait* trait = cp_trait_lookup::find (keyword_str, keyword_len);
>  
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:			 \
> -      kind = CPTK_##CODE;		 \
> -      binary = (ARITY == 2);		 \
> -      variadic = (ARITY == -1);		 \
> -      type = (TCC == tcc_type);		 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  tree type1, type2 = NULL_TREE;
> +  bool binary = (trait->arity == 2);
> +  bool variadic = (trait->arity == -1);
>  
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -11063,12 +11044,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    cp_lexer_consume_token (parser->lexer);
>  
>    matching_parens parens;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      cp_parser_require (parser, CPP_LESS, RT_LESS);
>    else
>      parens.require_open (parser);
>  
> -  if (kind == CPTK_IS_DEDUCIBLE)
> +  if (trait->kind == CPTK_IS_DEDUCIBLE)
>      {
>        const cp_token* token = cp_lexer_peek_token (parser->lexer);
>        type1 = cp_parser_id_expression (parser,
> @@ -11079,7 +11060,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  				       /*optional_p=*/false);
>        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
>      }
> -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* __type_pack_element takes an expression as its first argument and uses
>         template-id syntax instead of function call syntax (for consistency
>         with Clang).  We special case these properties of __type_pack_element
> @@ -11094,7 +11075,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    if (type1 == error_mark_node)
>      return error_mark_node;
>  
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      {
>        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
>        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> @@ -11144,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>      }
>  
>    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* cp_parser_enclosed_template_argument_list above already took care
>         of parsing the closing '>'.  */;
>    else
> @@ -11158,17 +11139,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  
>    /* Complete the trait expression, which may mean either processing
>       the trait expr now or saving it for template instantiation.  */
> -  switch (kind)
> +  switch (trait->kind)
>      {
>      case CPTK_BASES:
>        return cp_expr (finish_bases (type1, false), trait_loc);
>      case CPTK_DIRECT_BASES:
>        return cp_expr (finish_bases (type1, true), trait_loc);
>      default:
> -      if (type)
> -	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> +      if (trait->type)
> +	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
>        else
> -	return finish_trait_expr (trait_loc, kind, type1, type2);
> +	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
>      }
>  }
>  
> @@ -20081,11 +20062,8 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>  
>        return type;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    case RID_TRAIT_TYPE:
> +      type = cp_parser_trait (parser, token->u.value);
>        if (decl_specs)
>  	cp_parser_set_decl_spec_type (decl_specs, type,
>  				      token,
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 00/40] Optimize type traits performance
  2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
                             ` (38 preceding siblings ...)
  2023-10-11 21:46           ` [PATCH v17 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-13 21:03           ` Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 01/40] c++: Sort built-in traits alphabetically Ken Matsui
                               ` (40 more replies)
  39 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (40):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits through gperf
  c++: Accept the use of non-function-like built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/Make-lang.in			       |  26 ++
 gcc/cp/constraint.cc			       | 112 +++++--
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait-head.in		       |  30 ++
 gcc/cp/cp-trait.def			       |  27 +-
 gcc/cp/cp-trait.gperf			       |  91 ++++++
 gcc/cp/cp-trait.h			       | 285 ++++++++++++++++++
 gcc/cp/cp-tree.h			       |  14 +-
 gcc/cp/lex.cc				       |  19 ++
 gcc/cp/parser.cc			       | 144 ++++++---
 gcc/cp/semantics.cc			       | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 +++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C	       |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_signed.C	       |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 284 +++++++++++++++--
 33 files changed, 1784 insertions(+), 201 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 01/40] c++: Sort built-in traits alphabetically
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
@ 2023-10-13 21:03             ` Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
                               ` (39 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 01/40] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-13 21:03             ` Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 03/40] c++: Accept the use of non-function-like built-in trait identifiers Ken Matsui
                               ` (38 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses gperf to look up the specific trait. Rather than holding
traits as keywords, we set all trait identifiers as cik_trait, which is a new
cp_identifier_kind. As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait. Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* Make-lang.in: Add targets to generate cp-trait.gperf and
	cp-trait.h.
	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait identifier.
	* cp-tree.h (cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (init_cp_traits): New function to set cik_trait for all
	built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_lexer_lookup_trait): New function to look up a
	built-in trait from a token by gperf.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.
	* cp-trait-head.in: New file.
	* cp-trait.gperf: New file.
	* cp-trait.h: New file.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 --
 gcc/c-family/c-common.h   |   5 -
 gcc/cp/Make-lang.in       |  26 ++++
 gcc/cp/cp-objcp-common.cc |   8 +-
 gcc/cp/cp-trait-head.in   |  30 +++++
 gcc/cp/cp-trait.gperf     |  74 ++++++++++++
 gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
 gcc/cp/cp-tree.h          |  14 ++-
 gcc/cp/lex.cc             |  19 +++
 gcc/cp/parser.cc          | 132 ++++++++++++--------
 10 files changed, 492 insertions(+), 70 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2727fb7f8cc..a67d1c3e9f3 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -34,6 +34,8 @@
 # - the compiler proper (eg: cc1plus)
 # - define the names for selecting the language in LANGUAGES.
 
+AWK = @AWK@
+
 # Actual names to use when installing a native compiler.
 CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
 GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,30 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+# We always need the dependency on the .gperf file
+# because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from
+# cp-trait-head.in and cp-trait.def files.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
+	cat $< > $@
+	$(AWK) -F', *' '/^DEFTRAIT_/ { \
+		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+		gsub(/\)/, "", $$3); \
+		print $$2", CPTK_" $$1", "$$3", "type; \
+	}' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
new file mode 100644
index 00000000000..9357eea1238
--- /dev/null
+++ b/gcc/cp/cp-trait-head.in
@@ -0,0 +1,30 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
new file mode 100644
index 00000000000..47e3c1af499
--- /dev/null
+++ b/gcc/cp/cp-trait.gperf
@@ -0,0 +1,74 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
+"__is_abstract", CPTK_IS_ABSTRACT, 1, false
+"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
+"__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_class", CPTK_IS_CLASS, 1, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
+"__is_empty", CPTK_IS_EMPTY, 1, false
+"__is_enum", CPTK_IS_ENUM, 1, false
+"__is_final", CPTK_IS_FINAL, 1, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
+"__is_pod", CPTK_IS_POD, 1, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_same", CPTK_IS_SAME, 2, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
+"__is_trivial", CPTK_IS_TRIVIAL, 1, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_union", CPTK_IS_UNION, 1, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
+"__remove_cv", CPTK_REMOVE_CV, 1, true
+"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
+"__bases", CPTK_BASES, 1, true
+"__direct_bases", CPTK_DIRECT_BASES, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
new file mode 100644
index 00000000000..97ba8492d15
--- /dev/null
+++ b/gcc/cp/cp-trait.h
@@ -0,0 +1,247 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned char asso_values[] =
+    {
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
+       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
+      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
+      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        break;
+    }
+  return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 45,
+      MIN_WORD_LENGTH = 7,
+      MAX_WORD_LENGTH = 37,
+      MIN_HASH_VALUE = 7,
+      MAX_HASH_VALUE = 85
+    };
+
+  static const struct cp_trait wordlist[] =
+    {
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__bases", CPTK_BASES, 1, true},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+    };
+
+  static const signed char lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
+       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e34952da99..7baacfca0a7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Build-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..f6e1f6a4075 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,23 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  id = get_identifier (NAME); \
+  set_identifier_kind (id, cik_trait);
+#include "cp/cp-trait.def"
+#undef DEFTRAIT
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +342,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..39952893ffa 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "contracts.h"
 #include "bitmap.h"
 #include "builtins.h"
+#include "cp-trait.h"
 
 \f
 /* The lexer.  */
@@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  tree id = token->u.value;
+
+  if (token->type == CPP_NAME
+      && TREE_CODE (id) == IDENTIFIER_NODE
+      && IDENTIFIER_TRAIT_P (id))
+    {
+      const char *id_str = IDENTIFIER_POINTER (id);
+      const int id_len = IDENTIFIER_LENGTH (id);
+      return cp_trait_lookup::find (id_str, id_len);
+    }
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      {
+	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	if (trait)
+	  return cp_parser_trait (parser, trait);
+      }
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 03/40] c++: Accept the use of non-function-like built-in trait identifiers
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 01/40] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-13 21:03             ` [PATCH v18 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-13 21:03             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 04/40] c++: Implement __is_const built-in trait Ken Matsui
                               ` (37 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of non-function-like built-in trait
identifiers.  Specifically, we check if the subsequent token is '(' for
ordinary built-in traits or is '<' only for the special __type_pack_element
built-in trait.  If the same identifiers are used in other cases, the
parser treats them as normal identifiers.  This allows us to accept code
like:

struct __is_pointer {};

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 48 ++++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 39952893ffa..59015eac596 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -247,12 +247,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1183,21 +1183,33 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  tree id = token->u.value;
+  tree id = token1->u.value;
 
-  if (token->type == CPP_NAME
+  if (token1->type == CPP_NAME
       && TREE_CODE (id) == IDENTIFIER_NODE
       && IDENTIFIER_TRAIT_P (id))
     {
       const char *id_str = IDENTIFIER_POINTER (id);
       const int id_len = IDENTIFIER_LENGTH (id);
-      return cp_trait_lookup::find (id_str, id_len);
+      const cp_trait *trait = cp_trait_lookup::find (id_str, id_len);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (trait->kind == CPTK_TYPE_PACK_ELEMENT
+	  && token2->type != CPP_LESS)
+	return nullptr;
+      if (trait->kind != CPTK_TYPE_PACK_ELEMENT
+	  && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
+
+      return trait;
     }
   return nullptr;
 }
@@ -1206,9 +1218,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1219,9 +1231,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1236,7 +1248,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6108,7 +6120,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	 keyword.  */
     case CPP_NAME:
       {
-	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer, token);
 	if (trait)
 	  return cp_parser_trait (parser, trait);
       }
@@ -20117,7 +20129,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 04/40] c++: Implement __is_const built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (2 preceding siblings ...)
  2023-10-13 21:03             ` [PATCH v18 03/40] c++: Accept the use of non-function-like built-in trait identifiers Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
                               ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

	* Make-lang.in: Update key positions for gperf, based on
	automatically computed values.
	* cp-trait.def: Define __is_const.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/Make-lang.in                      |   2 +-
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 202 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_const.C      |  19 +++
 8 files changed, 135 insertions(+), 100 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index a67d1c3e9f3..7479e7dc00b 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -195,7 +195,7 @@ $(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
 else
 $(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
 endif
-	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+	gperf -o -C -E -k '6,8' -D -N 'find' -L C++ \
 		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
 
 # The cp-trait.gperf file itself is generated from
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47e3c1af499..47a5ec9ee6f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
+"__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
 "__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
 "__is_empty", CPTK_IS_EMPTY, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 97ba8492d15..c9005eee1ff 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -1,5 +1,5 @@
 /* C++ code produced by gperf version 3.1 */
-/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+/* Command-line: gperf -o -C -E -k 6,8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 79, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
-       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
-      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
-      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
+      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
+      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -104,6 +104,8 @@ cp_trait_lookup::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
       case 7:
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
         break;
     }
   return hval;
@@ -114,116 +116,118 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 85
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
-       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
-      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
-      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
-      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
+      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
+      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
+      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
+      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 05/40] libstdc++: Optimize is_const trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (3 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 04/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
                               ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 06/40] c++: Implement __is_volatile built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (4 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                               ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_volatile.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 ++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/cp-trait.gperf                    |  1 +
 gcc/cp/cp-trait.h                        | 38 +++++++++++++-----------
 gcc/cp/semantics.cc                      |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C   | 19 ++++++++++++
 7 files changed, 51 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47a5ec9ee6f..ea7abda6c75 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index c9005eee1ff..f462794d5db 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
       40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
       96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,27 +125,29 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
@@ -159,9 +161,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -215,19 +217,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
-      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
-      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
-      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
-      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
+      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
+      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 07/40] libstdc++: Optimize is_volatile trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (5 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 08/40] c++: Implement __is_array built-in trait Ken Matsui
                               ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 08/40] c++: Implement __is_array built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (6 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
                               ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 148 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_array.C      |  28 +++++
 7 files changed, 116 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ea7abda6c75..fb162cac164 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f462794d5db..526e63dec42 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
-      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
-      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
+       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
+       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,108 +116,110 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 47,
+      TOTAL_KEYWORDS = 48,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -226,10 +228,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
       14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
-      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 47
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 09/40] libstdc++: Optimize is_array trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (7 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 08/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                               ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 10/40] c++: Implement __is_unbounded_array built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (8 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                               ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unbounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNBOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 42 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 ++++++++++++++++
 7 files changed, 71 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index fb162cac164..a894fc8c74c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 526e63dec42..47060ffbbef 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 48,
+      TOTAL_KEYWORDS = 49,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,30 +125,32 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
@@ -161,9 +163,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -219,21 +221,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
-      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
+      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
+      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 47
+      -1, -1, -1, 48
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 11/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (9 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                               ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 12/40] c++: Implement __is_bounded_array built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (10 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                               ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_bounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_BOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |  3 +
 gcc/cp/cp-trait.def                         |  1 +
 gcc/cp/cp-trait.gperf                       |  1 +
 gcc/cp/cp-trait.h                           | 86 +++++++++++----------
 gcc/cp/semantics.cc                         |  4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  3 +
 gcc/testsuite/g++.dg/ext/is_bounded_array.C | 38 +++++++++
 7 files changed, 94 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index a894fc8c74c..90fcdc01de6 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false
 "__is_class", CPTK_IS_CLASS, 1, false
 "__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 47060ffbbef..f22a6e93618 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
        50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
       116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 49,
+      TOTAL_KEYWORDS = 50,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,54 +125,56 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -181,7 +183,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -191,27 +193,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
@@ -219,9 +221,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -230,12 +232,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
-      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
+      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
+      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 48
+      -1, -1, -1, 49
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 13/40] libstdc++: Optimize is_bounded_array trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (11 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                               ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 14/40] c++: Implement __is_scoped_enum built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (12 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                               ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scoped_enum.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCOPED_ENUM.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                      |   3 +
 gcc/cp/cp-trait.def                       |   1 +
 gcc/cp/cp-trait.gperf                     |   1 +
 gcc/cp/cp-trait.h                         | 161 +++++++++++-----------
 gcc/cp/semantics.cc                       |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |   3 +
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C |  67 +++++++++
 7 files changed, 160 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90fcdc01de6..f3fd82ba549 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -59,6 +59,7 @@ struct cp_trait {
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f22a6e93618..9c18165eb68 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
-       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
-      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
+      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
+      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
+      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,56 +116,60 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 50,
+      TOTAL_KEYWORDS = 51,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -173,22 +177,18 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
@@ -197,47 +197,48 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
-      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 49
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
+      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
+      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
+      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
+      50
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 15/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (13 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                               ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 16/40] c++: Implement __is_member_pointer built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (14 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                               ` (24 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_MEMBER_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 153 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_member_pointer.C |  30 ++++
 7 files changed, 120 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index f3fd82ba549..3775b11283d 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 9c18165eb68..dfd60cec6e6 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 111, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
-      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
-      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
-      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
+       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
+       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
+      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118
     };
   unsigned int hval = len;
 
@@ -116,69 +116,67 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 51,
+      TOTAL_KEYWORDS = 52,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 117
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -187,58 +185,63 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
-      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
-      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
-      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
-      50
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
+      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
+      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
+      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
+      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
+      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, 51
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 17/40] libstdc++: Optimize is_member_pointer trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (15 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                               ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (16 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                               ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_function_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_FUNCTION_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |   3 +
 gcc/cp/cp-trait.def                           |   1 +
 gcc/cp/cp-trait.gperf                         |   1 +
 gcc/cp/cp-trait.h                             | 176 +++++++++---------
 gcc/cp/semantics.cc                           |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |   3 +
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 7 files changed, 131 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 3775b11283d..b28efbab322 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index dfd60cec6e6..d3d4bdf9799 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 111, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
-       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
-       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
-      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
+      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
+      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
+      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -116,132 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 52,
+      TOTAL_KEYWORDS = 53,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 117
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
-      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
-      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
-      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
-      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
-      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, 51
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
+      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (17 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                               ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (18 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                               ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_object_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_OBJECT_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 +
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 62 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 +
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++
 7 files changed, 74 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index b28efbab322..32199a1fe9a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
+"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index d3d4bdf9799..799fe2b792f 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 53,
+      TOTAL_KEYWORDS = 54,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,57 +125,57 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,25 +185,25 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
@@ -211,12 +211,14 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
@@ -229,7 +231,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -240,8 +242,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
       -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
-      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
+      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (19 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                               ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 22/40] c++: Implement __is_reference built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (20 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                               ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_reference.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 113 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_reference.C  |  34 +++++++
 7 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 32199a1fe9a..5989b84727f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 799fe2b792f..f0b4f96d4a9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 94, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
-      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
-      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
-      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
+       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
+       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
+      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   unsigned int hval = len;
 
@@ -116,58 +116,58 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 54,
+      TOTAL_KEYWORDS = 55,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 100
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -175,7 +175,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,7 +185,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -207,15 +207,13 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
@@ -223,6 +221,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,8 +231,10 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false}
     };
 
   static const signed char lookup[] =
@@ -241,9 +243,10 @@ cp_trait_lookup::find (const char *str, size_t len)
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
+      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      -1, -1, 54
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 23/40] libstdc++: Optimize is_reference trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (21 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 24/40] c++: Implement __is_function built-in trait Ken Matsui
                               ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 24/40] c++: Implement __is_function built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (22 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                               ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_function.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 143 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_function.C   |  58 +++++++++
 7 files changed, 143 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5989b84727f..771242a7f45 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -50,6 +50,7 @@ struct cp_trait {
 "__is_empty", CPTK_IS_EMPTY, 1, false
 "__is_enum", CPTK_IS_ENUM, 1, false
 "__is_final", CPTK_IS_FINAL, 1, false
+"__is_function", CPTK_IS_FUNCTION, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f0b4f96d4a9..b6db58e93c9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 94, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
-       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
-       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
-      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
+       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
+       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
+      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,113 +116,113 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 55,
+      TOTAL_KEYWORDS = 56,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 100
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,10 +231,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false}
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
@@ -242,11 +244,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
-      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      -1, -1, 54
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
+      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 55
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 25/40] libstdc++: Optimize is_function trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (23 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 26/40] libstdc++: Optimize is_object " Ken Matsui
                               ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 26/40] libstdc++: Optimize is_object trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (24 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                               ` (14 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 27/40] c++: Implement __remove_pointer built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (25 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                               ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/cp-trait.gperf                     |  1 +
 gcc/cp/cp-trait.h                         | 32 +++++++-------
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 6 files changed, 78 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 771242a7f45..8fbd67788d5 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -77,6 +77,7 @@ struct cp_trait {
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
 "__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_pointer", CPTK_REMOVE_POINTER, 1, true
 "__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
 "__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
 "__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b6db58e93c9..ad2c2a2d250 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 56,
+      TOTAL_KEYWORDS = 57,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,7 +125,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
@@ -137,17 +137,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
@@ -235,21 +237,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
-      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 55
+       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
+      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
+      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
+      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 56
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (26 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
                               ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 29/40] c++: Implement __is_pointer built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (27 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                               ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 155 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_pointer.C    |  51 ++++++++
 7 files changed, 141 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 8fbd67788d5..5d40e04f91c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
+"__is_pointer", CPTK_IS_POINTER, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ad2c2a2d250..ab783b161c7 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
-       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
-       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
-      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
+       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
+      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
+      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,78 +116,78 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 57,
+      TOTAL_KEYWORDS = 58,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -205,23 +205,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_array", CPTK_IS_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
@@ -236,22 +240,19 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
-      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
       25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
-      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
-      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 56
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
+      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
+      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      57
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 30/40] libstdc++: Optimize is_pointer trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (28 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
                               ` (10 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..cd5ce45951f 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 31/40] c++: Implement __is_arithmetic built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (29 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                               ` (9 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_arithmetic.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 184 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_arithmetic.C |  33 ++++
 7 files changed, 138 insertions(+), 91 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5d40e04f91c..9050c36f105 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ab783b161c7..31fd5075f2d 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 97, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
-       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
-      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
-      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
+        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
+       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
+      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104
     };
   unsigned int hval = len;
 
@@ -116,130 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 58,
+      TOTAL_KEYWORDS = 59,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 103
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
@@ -247,12 +249,12 @@ cp_trait_lookup::find (const char *str, size_t len)
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
-      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      57
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
+      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
+      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
+      -1, -1, 57, -1, -1, 58
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (30 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                               ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (31 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 34/40] libstdc++: Optimize is_compound " Ken Matsui
                               ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 34/40] libstdc++: Optimize is_compound trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (32 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                               ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 35/40] c++: Implement __is_unsigned built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (33 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                               ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unsigned.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNSIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 118 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_unsigned.C   |  47 +++++++++
 7 files changed, 120 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 9050c36f105..90d05bca5c1 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -74,6 +74,7 @@ struct cp_trait {
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_unsigned", CPTK_IS_UNSIGNED, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 31fd5075f2d..75ab2b5edfa 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 97, duplicates = 0 */
+/* maximum key range = 129, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
-        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
-       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
-      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
+       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
+       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
+      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136
     };
   unsigned int hval = len;
 
@@ -116,46 +116,44 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 59,
+      TOTAL_KEYWORDS = 60,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 103
+      MAX_HASH_VALUE = 135
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
@@ -165,11 +163,11 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -180,7 +178,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
 #line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -207,6 +205,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
@@ -223,8 +223,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 70 "../../gcc/cp/cp-trait.gperf"
@@ -242,19 +242,23 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
-      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
-      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
+       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
+      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
       -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58
+      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (34 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 37/40] c++: Implement __is_signed built-in trait Ken Matsui
                               ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 37/40] c++: Implement __is_signed built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (35 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                               ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_signed.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_signed.
	* g++.dg/ext/is_signed.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 211 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_signed.C     |  47 +++++
 7 files changed, 165 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90d05bca5c1..de0ba162e7a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 75ab2b5edfa..6d1078de2fe 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 129, duplicates = 0 */
+/* maximum key range = 119, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
-       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
-       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
-      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
+       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
+       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
+      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126
     };
   unsigned int hval = len;
 
@@ -116,149 +116,150 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 60,
+      TOTAL_KEYWORDS = 61,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 135
+      MAX_HASH_VALUE = 125
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_signed", CPTK_IS_SIGNED, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 36 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 37 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
-      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
+       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
+      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
+      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
+      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
+      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 38/40] libstdc++: Optimize is_signed trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (36 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 37/40] c++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
                               ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 39/40] c++: Implement __is_scalar built-in trait
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (37 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 21:04             ` [PATCH v18 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scalar.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCALAR.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 186 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_scalar.C     |  31 ++++
 7 files changed, 137 insertions(+), 92 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index de0ba162e7a..ef51c713c58 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scalar", CPTK_IS_SCALAR, 1, false
 "__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 6d1078de2fe..8c68af420f9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -78,10 +78,10 @@ cp_trait_lookup::hash (const char *str, size_t len)
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
-       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
-       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
-      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  40, 126,  25,  21,  50,
+        0,   0,  30,  10, 126,   0, 126, 126,  25,   5,
+       50,   0,  61, 126,  10,  10,   5,   0,  15, 126,
+      126,   5, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 61,
+      TOTAL_KEYWORDS = 62,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,141 +125,143 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 89 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_signed", CPTK_IS_SIGNED, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 33 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 32 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scalar", CPTK_IS_SCALAR, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
-      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
-      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
-      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
-      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5,  6,  7,  8,  9, -1, -1, -1, 10, 11, -1, 12, 13,
+      14, 15, 16, 17, -1, 18, -1, 19, 20, 21, 22, 23, 24, 25,
+      26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
+      -1, -1, 38, -1, 39, -1, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, 45, -1, 46, 47, 48, -1, -1, 49, 50, 51, 52, -1, -1,
+      -1, 53, -1, -1, -1, -1, 54, -1, -1, 55, -1, -1, -1, -1,
+      56, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, 58, -1,
+      -1, -1, -1, -1, 59, -1, 60, -1, -1, -1, -1, -1, -1, 61
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v18 40/40] libstdc++: Optimize is_scalar trait performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (38 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-13 21:04             ` Ken Matsui
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 21:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 00/40] Optimize type traits performance
  2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
                               ` (39 preceding siblings ...)
  2023-10-13 21:04             ` [PATCH v18 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-13 22:37             ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 01/40] c++: Sort built-in traits alphabetically Ken Matsui
                                 ` (40 more replies)
  40 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (40):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits through gperf
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/Make-lang.in			       |  26 ++
 gcc/cp/constraint.cc			       | 112 +++++--
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait-head.in		       |  30 ++
 gcc/cp/cp-trait.def			       |  27 +-
 gcc/cp/cp-trait.gperf			       |  91 ++++++
 gcc/cp/cp-trait.h			       | 285 ++++++++++++++++++
 gcc/cp/cp-tree.h			       |  14 +-
 gcc/cp/lex.cc				       |  19 ++
 gcc/cp/parser.cc			       | 144 ++++++---
 gcc/cp/semantics.cc			       | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 +++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C	       |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_signed.C	       |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 284 +++++++++++++++--
 33 files changed, 1784 insertions(+), 201 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 01/40] c++: Sort built-in traits alphabetically
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
                                 ` (39 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 01/40] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-15 20:43                 ` Patrick Palka
  2023-10-13 22:37               ` [PATCH v19 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
                                 ` (38 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses gperf to look up the specific trait.  Rather than holding
traits as keywords, we set all trait identifiers as cik_trait, which is a new
cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* Make-lang.in: Add targets to generate cp-trait.gperf and
	cp-trait.h.
	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait identifier.
	* cp-tree.h (cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (init_cp_traits): New function to set cik_trait for all
	built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_lexer_lookup_trait): New function to look up a
	built-in trait from a token by gperf.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.
	* cp-trait-head.in: New file.
	* cp-trait.gperf: New file.
	* cp-trait.h: New file.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 --
 gcc/c-family/c-common.h   |   5 -
 gcc/cp/Make-lang.in       |  26 ++++
 gcc/cp/cp-objcp-common.cc |   8 +-
 gcc/cp/cp-trait-head.in   |  30 +++++
 gcc/cp/cp-trait.gperf     |  74 ++++++++++++
 gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
 gcc/cp/cp-tree.h          |  14 ++-
 gcc/cp/lex.cc             |  19 +++
 gcc/cp/parser.cc          | 132 ++++++++++++--------
 10 files changed, 492 insertions(+), 70 deletions(-)
 create mode 100644 gcc/cp/cp-trait-head.in
 create mode 100644 gcc/cp/cp-trait.gperf
 create mode 100644 gcc/cp/cp-trait.h

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2727fb7f8cc..a67d1c3e9f3 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -34,6 +34,8 @@
 # - the compiler proper (eg: cc1plus)
 # - define the names for selecting the language in LANGUAGES.
 
+AWK = @AWK@
+
 # Actual names to use when installing a native compiler.
 CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
 GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,30 @@ endif
 # This is the file that depends on the generated header file.
 cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
 
+# We always need the dependency on the .gperf file
+# because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from
+# cp-trait-head.in and cp-trait.def files.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
+	cat $< > $@
+	$(AWK) -F', *' '/^DEFTRAIT_/ { \
+		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+		gsub(/\)/, "", $$3); \
+		print $$2", CPTK_" $$1", "$$3", "type; \
+	}' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
 components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
 components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
new file mode 100644
index 00000000000..9357eea1238
--- /dev/null
+++ b/gcc/cp/cp-trait-head.in
@@ -0,0 +1,30 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
new file mode 100644
index 00000000000..47e3c1af499
--- /dev/null
+++ b/gcc/cp/cp-trait.gperf
@@ -0,0 +1,74 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+%}
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
+"__is_abstract", CPTK_IS_ABSTRACT, 1, false
+"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
+"__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_class", CPTK_IS_CLASS, 1, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
+"__is_empty", CPTK_IS_EMPTY, 1, false
+"__is_enum", CPTK_IS_ENUM, 1, false
+"__is_final", CPTK_IS_FINAL, 1, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
+"__is_pod", CPTK_IS_POD, 1, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_same", CPTK_IS_SAME, 2, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
+"__is_trivial", CPTK_IS_TRIVIAL, 1, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_union", CPTK_IS_UNION, 1, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
+"__remove_cv", CPTK_REMOVE_CV, 1, true
+"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
+"__bases", CPTK_BASES, 1, true
+"__direct_bases", CPTK_DIRECT_BASES, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
new file mode 100644
index 00000000000..97ba8492d15
--- /dev/null
+++ b/gcc/cp/cp-trait.h
@@ -0,0 +1,247 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+  const char *name;
+  enum cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+  static const unsigned char asso_values[] =
+    {
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
+       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
+      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
+      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+      86, 86, 86, 86, 86, 86
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        break;
+    }
+  return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 45,
+      MIN_WORD_LENGTH = 7,
+      MAX_WORD_LENGTH = 37,
+      MIN_HASH_VALUE = 7,
+      MAX_HASH_VALUE = 85
+    };
+
+  static const struct cp_trait wordlist[] =
+    {
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__bases", CPTK_BASES, 1, true},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+    };
+
+  static const signed char lookup[] =
+    {
+      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
+       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          int index = lookup[key];
+
+          if (index >= 0)
+            {
+              const char *s = wordlist[index].name;
+
+              if (*str == *s && !strcmp (str + 1, s + 1))
+                return &wordlist[index];
+            }
+        }
+    }
+  return 0;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e34952da99..62e134886fb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..f6e1f6a4075 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,23 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  id = get_identifier (NAME); \
+  set_identifier_kind (id, cik_trait);
+#include "cp/cp-trait.def"
+#undef DEFTRAIT
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +342,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..39952893ffa 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "contracts.h"
 #include "bitmap.h"
 #include "builtins.h"
+#include "cp-trait.h"
 
 \f
 /* The lexer.  */
@@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  tree id = token->u.value;
+
+  if (token->type == CPP_NAME
+      && TREE_CODE (id) == IDENTIFIER_NODE
+      && IDENTIFIER_TRAIT_P (id))
+    {
+      const char *id_str = IDENTIFIER_POINTER (id);
+      const int id_len = IDENTIFIER_LENGTH (id);
+      return cp_trait_lookup::find (id_str, id_len);
+    }
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      {
+	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	if (trait)
+	  return cp_parser_trait (parser, trait);
+      }
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 03/40] c++: Accept the use of built-in trait identifiers
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 01/40] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 04/40] c++: Implement __is_const built-in trait Ken Matsui
                                 ` (37 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 48 ++++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 39952893ffa..59015eac596 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -247,12 +247,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1183,21 +1183,33 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  tree id = token->u.value;
+  tree id = token1->u.value;
 
-  if (token->type == CPP_NAME
+  if (token1->type == CPP_NAME
       && TREE_CODE (id) == IDENTIFIER_NODE
       && IDENTIFIER_TRAIT_P (id))
     {
       const char *id_str = IDENTIFIER_POINTER (id);
       const int id_len = IDENTIFIER_LENGTH (id);
-      return cp_trait_lookup::find (id_str, id_len);
+      const cp_trait *trait = cp_trait_lookup::find (id_str, id_len);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (trait->kind == CPTK_TYPE_PACK_ELEMENT
+	  && token2->type != CPP_LESS)
+	return nullptr;
+      if (trait->kind != CPTK_TYPE_PACK_ELEMENT
+	  && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
+
+      return trait;
     }
   return nullptr;
 }
@@ -1206,9 +1218,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1219,9 +1231,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1236,7 +1248,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6108,7 +6120,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	 keyword.  */
     case CPP_NAME:
       {
-	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer, token);
 	if (trait)
 	  return cp_parser_trait (parser, trait);
       }
@@ -20117,7 +20129,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 04/40] c++: Implement __is_const built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (2 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
                                 ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

	* Make-lang.in: Update key positions for gperf, based on
	automatically computed values.
	* cp-trait.def: Define __is_const.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_CONST.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/Make-lang.in                      |   2 +-
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 202 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_const.C      |  19 +++
 8 files changed, 135 insertions(+), 100 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index a67d1c3e9f3..7479e7dc00b 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -195,7 +195,7 @@ $(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
 else
 $(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
 endif
-	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+	gperf -o -C -E -k '6,8' -D -N 'find' -L C++ \
 		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
 
 # The cp-trait.gperf file itself is generated from
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47e3c1af499..47a5ec9ee6f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
+"__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
 "__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
 "__is_empty", CPTK_IS_EMPTY, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 97ba8492d15..c9005eee1ff 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -1,5 +1,5 @@
 /* C++ code produced by gperf version 3.1 */
-/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
+/* Command-line: gperf -o -C -E -k 6,8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 79, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
-       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
-      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
-      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
-      86, 86, 86, 86, 86, 86
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
+      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
+      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -104,6 +104,8 @@ cp_trait_lookup::hash (const char *str, size_t len)
         hval += asso_values[static_cast<unsigned char>(str[7])];
       /*FALLTHROUGH*/
       case 7:
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
         break;
     }
   return hval;
@@ -114,116 +116,118 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 45,
+      TOTAL_KEYWORDS = 46,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 85
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
-       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
-      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
-      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
-      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
+      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
+      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
+      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
+      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 05/40] libstdc++: Optimize is_const trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (3 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 04/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
                                 ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 06/40] c++: Implement __is_volatile built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (4 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                                 ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_volatile.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_VOLATILE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 ++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/cp-trait.gperf                    |  1 +
 gcc/cp/cp-trait.h                        | 38 +++++++++++++-----------
 gcc/cp/semantics.cc                      |  4 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C   | 19 ++++++++++++
 7 files changed, 51 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 47a5ec9ee6f..ea7abda6c75 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index c9005eee1ff..f462794d5db 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
       40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0, 96, 96,
+      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
       96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
       96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 46,
+      TOTAL_KEYWORDS = 47,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,27 +125,29 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
@@ -159,9 +161,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -215,19 +217,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, -1, 10, -1, 11, 12,
-      13, -1, 14, -1, 15, 16, -1, 17, -1, 18, 19, -1, 20, -1,
-      21, -1, 22, 23, -1, 24, 25, 26, 27, -1, 28, 29, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, -1, 36, 37, 38, -1, 39, -1,
-      40, -1, -1, 41, -1, 42, -1, -1, -1, -1, 43, -1, -1, -1,
-      -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
+      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
+      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 07/40] libstdc++: Optimize is_volatile trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (5 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 08/40] c++: Implement __is_array built-in trait Ken Matsui
                                 ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 08/40] c++: Implement __is_array built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (6 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
                                 ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 148 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_array.C      |  28 +++++
 7 files changed, 116 insertions(+), 72 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index ea7abda6c75..fb162cac164 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
 "__is_class", CPTK_IS_CLASS, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f462794d5db..526e63dec42 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 35, 10, 20,
-      40,  0, 30, 15, 96,  0, 96, 96,  5, 15,
-      30,  0,  5, 96, 10, 25,  5,  0,  5, 96,
-      96,  5, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
+       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
+       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,108 +116,110 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 47,
+      TOTAL_KEYWORDS = 48,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -226,10 +228,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
       14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, -1, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, 42, -1, 43, -1, -1, -1, -1, 44, -1, -1, -1,
-      -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46
+      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
+      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
+      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 47
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 09/40] libstdc++: Optimize is_array trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (7 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 08/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                 ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 10/40] c++: Implement __is_unbounded_array built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (8 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                                 ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unbounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNBOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 ++
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 42 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 ++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C | 37 ++++++++++++++++
 7 files changed, 71 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index fb162cac164..a894fc8c74c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -63,6 +63,7 @@ struct cp_trait {
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
 "__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 526e63dec42..47060ffbbef 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 48,
+      TOTAL_KEYWORDS = 49,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,30 +125,32 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
@@ -161,9 +163,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -219,21 +221,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, -1, 12, 13,
-      14, -1, 15, -1, 16, 17, -1, 18, -1, 19, 20, -1, 21, -1,
-      22, -1, 23, 24, -1, 25, 26, 27, 28, -1, 29, -1, 30, 31,
-      -1, -1, 32, 33, 34, 35, -1, 36, 37, 38, 39, -1, 40, -1,
-      41, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 43, -1, -1, 44, -1, 45, -1, -1, -1, -1, 46, -1, -1,
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
+      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
+      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 47
+      -1, -1, -1, 48
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 11/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (9 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                 ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 12/40] c++: Implement __is_bounded_array built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (10 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                                 ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_bounded_array.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_BOUNDED_ARRAY.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                        |  3 +
 gcc/cp/cp-trait.def                         |  1 +
 gcc/cp/cp-trait.gperf                       |  1 +
 gcc/cp/cp-trait.h                           | 86 +++++++++++----------
 gcc/cp/semantics.cc                         |  4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C    |  3 +
 gcc/testsuite/g++.dg/ext/is_bounded_array.C | 38 +++++++++
 7 files changed, 94 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index a894fc8c74c..90fcdc01de6 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -42,6 +42,7 @@ struct cp_trait {
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false
 "__is_class", CPTK_IS_CLASS, 1, false
 "__is_const", CPTK_IS_CONST, 1, false
 "__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 47060ffbbef..f22a6e93618 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -80,7 +80,7 @@ cp_trait_lookup::hash (const char *str, size_t len)
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
        50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,   5, 116,
+       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
       116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
       116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 49,
+      TOTAL_KEYWORDS = 50,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,54 +125,56 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
+#line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -181,7 +183,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -191,27 +193,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
@@ -219,9 +221,9 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -230,12 +232,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, -1, 24, 25, -1, 26, 27, 28, 29, -1, 30, -1, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, -1, 41, -1,
-      42, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 44, -1, -1, 45, -1, 46, -1, -1, -1, -1, 47, -1, -1,
+      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
+      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 48
+      -1, -1, -1, 49
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 13/40] libstdc++: Optimize is_bounded_array trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (11 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                 ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 14/40] c++: Implement __is_scoped_enum built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (12 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                                 ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scoped_enum.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCOPED_ENUM.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                      |   3 +
 gcc/cp/cp-trait.def                       |   1 +
 gcc/cp/cp-trait.gperf                     |   1 +
 gcc/cp/cp-trait.h                         | 161 +++++++++++-----------
 gcc/cp/semantics.cc                       |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |   3 +
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C |  67 +++++++++
 7 files changed, 160 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90fcdc01de6..f3fd82ba549 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -59,6 +59,7 @@ struct cp_trait {
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
 "__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f22a6e93618..9c18165eb68 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  45,   5,  20,
-       50,   0,  30,   5, 116,   0, 116, 116,   5,  10,
-       30,   0,   5, 116,  10,  30,   5,   0,  25, 116,
-      116,   5, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
+      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
+      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
+      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,56 +116,60 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 50,
+      TOTAL_KEYWORDS = 51,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -173,22 +177,18 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
@@ -197,47 +197,48 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
-      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, -1, 17, 18, -1, 19, -1, 20, 21, -1, 22, -1,
-      23, 24, 25, 26, -1, 27, 28, 29, 30, -1, 31, -1, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, 39, 40, 41, -1, 42, -1,
-      43, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, 45, -1, -1, 46, -1, 47, -1, -1, -1, -1, 48, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 49
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
+      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
+      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
+      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
+      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
+      50
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 15/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (13 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                 ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 16/40] c++: Implement __is_member_pointer built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (14 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                                 ` (24 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_MEMBER_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                         |   3 +
 gcc/cp/cp-trait.def                          |   1 +
 gcc/cp/cp-trait.gperf                        |   1 +
 gcc/cp/cp-trait.h                            | 153 ++++++++++---------
 gcc/cp/semantics.cc                          |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C     |   3 +
 gcc/testsuite/g++.dg/ext/is_member_pointer.C |  30 ++++
 7 files changed, 120 insertions(+), 75 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index f3fd82ba549..3775b11283d 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 9c18165eb68..dfd60cec6e6 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 111, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99,  0,  5, 50,
-      30,  0, 40, 15, 99,  0, 99, 99,  5, 10,
-      30,  0,  5, 99, 10, 50,  5,  0, 35, 99,
-      99,  5, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
+       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
+       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
+      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
+      118, 118, 118, 118, 118, 118
     };
   unsigned int hval = len;
 
@@ -116,69 +116,67 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 51,
+      TOTAL_KEYWORDS = 52,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 117
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -187,58 +185,63 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false}
+      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, 13, 14, 15,
-      16, 17, 18, -1, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, -1, 29, -1, 30, -1, -1, 31, 32, 33,
-      -1, -1, 34, 35, 36, 37, -1, 38, -1, 39, 40, 41, -1, 42,
-      43, -1, 44, -1, -1, 45, -1, -1, -1, -1, 46, -1, -1, -1,
-      -1, 47, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1,
-      50
+       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
+      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
+      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
+      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
+      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
+      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
+      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, 51
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 17/40] libstdc++: Optimize is_member_pointer trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (15 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                 ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (16 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                                 ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_function_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_FUNCTION_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |   3 +
 gcc/cp/cp-trait.def                           |   1 +
 gcc/cp/cp-trait.gperf                         |   1 +
 gcc/cp/cp-trait.h                             | 176 +++++++++---------
 gcc/cp/semantics.cc                           |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |   3 +
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 7 files changed, 131 insertions(+), 88 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 3775b11283d..b28efbab322 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -52,6 +52,7 @@ struct cp_trait {
 "__is_final", CPTK_IS_FINAL, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index dfd60cec6e6..d3d4bdf9799 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 111, duplicates = 0 */
+/* maximum key range = 89, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118,  20, 118,   0,  55,  50,
-       40,   0,  40,  20, 118,   0, 118, 118,   5,   5,
-       30,   0,   5, 118,  10,  50,   5,   0,   5, 118,
-      118,   5, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
-      118, 118, 118, 118, 118, 118
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
+      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
+      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
+      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+      96, 96, 96, 96, 96, 96
     };
   unsigned int hval = len;
 
@@ -116,132 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 52,
+      TOTAL_KEYWORDS = 53,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 117
+      MAX_HASH_VALUE = 95
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 75 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 42 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false}
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8,  9, -1, 10, 11, 12, -1, 13, 14,
-      15, 16, 17, -1, 18, 19, 20, 21, -1, 22, 23, -1, 24, -1,
-      25, -1, 26, 27, -1, -1, 28, -1, 29, -1, -1, 30, 31, 32,
-      -1, -1, 33, 34, 35, 36, -1, 37, 38, 39, 40, 41, -1, -1,
-      42, -1, -1, 43, -1, 44, -1, -1, -1, -1, 45, -1, -1, -1,
-      -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, 48, 49, -1,
-      50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, 51
+       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
+      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
+      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (17 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                 ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (18 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                                 ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_member_object_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle
	CPTK_IS_MEMBER_OBJECT_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                          |  3 +
 gcc/cp/cp-trait.def                           |  1 +
 gcc/cp/cp-trait.gperf                         |  1 +
 gcc/cp/cp-trait.h                             | 62 ++++++++++---------
 gcc/cp/semantics.cc                           |  4 ++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  3 +
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++
 7 files changed, 74 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index b28efbab322..32199a1fe9a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -53,6 +53,7 @@ struct cp_trait {
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
+"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false
 "__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false
 "__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
 "__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index d3d4bdf9799..799fe2b792f 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 53,
+      TOTAL_KEYWORDS = 54,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,57 +125,57 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,25 +185,25 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
@@ -211,12 +211,14 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
@@ -229,7 +231,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
@@ -240,8 +242,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
       -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, -1, -1, 46, -1, 47, -1, -1, -1,
-      -1, 48, 49, -1, 50, -1, 51, -1, -1, -1, -1, 52
+      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (19 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                                 ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 22/40] c++: Implement __is_reference built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (20 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                                 ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_reference.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_REFERENCE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 113 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_reference.C  |  34 +++++++
 7 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 32199a1fe9a..5989b84727f 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 799fe2b792f..f0b4f96d4a9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 89, duplicates = 0 */
+/* maximum key range = 94, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 20, 96, 40,  5, 40,
-      40,  0, 25, 10, 96,  0, 96, 96,  5, 25,
-      30,  0,  5, 96, 10, 15,  5,  0, 25, 96,
-      96, 20, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
-      96, 96, 96, 96, 96, 96
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
+       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
+       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
+      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+      101, 101, 101, 101, 101, 101
     };
   unsigned int hval = len;
 
@@ -116,58 +116,58 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 54,
+      TOTAL_KEYWORDS = 55,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 95
+      MAX_HASH_VALUE = 100
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -175,7 +175,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
@@ -185,7 +185,7 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -207,15 +207,13 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
@@ -223,6 +221,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,8 +231,10 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false}
     };
 
   static const signed char lookup[] =
@@ -241,9 +243,10 @@ cp_trait_lookup::find (const char *str, size_t len)
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
       24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, 41, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, -1, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53
+      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
+      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      -1, -1, 54
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 23/40] libstdc++: Optimize is_reference trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (21 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 24/40] c++: Implement __is_function built-in trait Ken Matsui
                                 ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 24/40] c++: Implement __is_function built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (22 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                                 ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_function.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_FUNCTION.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 143 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_function.C   |  58 +++++++++
 7 files changed, 143 insertions(+), 70 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5989b84727f..771242a7f45 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -50,6 +50,7 @@ struct cp_trait {
 "__is_empty", CPTK_IS_EMPTY, 1, false
 "__is_enum", CPTK_IS_ENUM, 1, false
 "__is_final", CPTK_IS_FINAL, 1, false
+"__is_function", CPTK_IS_FUNCTION, 1, false
 "__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
 "__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
 "__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index f0b4f96d4a9..b6db58e93c9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 94, duplicates = 0 */
+/* maximum key range = 109, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101,  20, 101,  40,   5,  40,
-       40,   0,  60,  10, 101,   0, 101, 101,   5,  25,
-       30,   0,   5, 101,  10,  15,   5,   0,  25, 101,
-      101,  20, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
-      101, 101, 101, 101, 101, 101
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
+       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
+       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
+      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+      116, 116, 116, 116, 116, 116
     };
   unsigned int hval = len;
 
@@ -116,113 +116,113 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 55,
+      TOTAL_KEYWORDS = 56,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 100
+      MAX_HASH_VALUE = 115
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
+#line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
@@ -231,10 +231,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false}
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
@@ -242,11 +244,12 @@ cp_trait_lookup::find (const char *str, size_t len)
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
       15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, 33, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, -1, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, -1, 47, -1, -1, -1,
-      48, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      -1, -1, 54
+      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
+      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
+      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
+      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
+      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 55
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 25/40] libstdc++: Optimize is_function trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (23 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 26/40] libstdc++: Optimize is_object " Ken Matsui
                                 ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 26/40] libstdc++: Optimize is_object trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (24 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                                 ` (14 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 27/40] c++: Implement __remove_pointer built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (25 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                                 ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/cp-trait.gperf                     |  1 +
 gcc/cp/cp-trait.h                         | 32 +++++++-------
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 6 files changed, 78 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 771242a7f45..8fbd67788d5 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -77,6 +77,7 @@ struct cp_trait {
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
 "__remove_cv", CPTK_REMOVE_CV, 1, true
 "__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_pointer", CPTK_REMOVE_POINTER, 1, true
 "__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
 "__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
 "__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index b6db58e93c9..ad2c2a2d250 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 56,
+      TOTAL_KEYWORDS = 57,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,7 +125,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
@@ -137,17 +137,19 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
@@ -235,21 +237,21 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5, -1,  6,  7,  8, -1, -1,  9, 10, 11, 12, 13, 14,
-      15, -1, 16, 17, 18, 19, -1, 20, -1, 21, 22, -1, 23, -1,
-      24, 25, 26, 27, -1, 28, 29, 30, 31, -1, 32, -1, 33, 34,
-      -1, -1, 35, 36, 37, 38, -1, 39, 40, -1, -1, -1, 41, 42,
-      43, -1, -1, -1, -1, 44, 45, -1, 46, 47, 48, -1, -1, -1,
-      -1, 49, 50, -1, 51, -1, 52, -1, -1, -1, -1, 53, -1, -1,
-      54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 55
+       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
+      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
+      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
+      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
+      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, 56
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (26 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
                                 ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 29/40] c++: Implement __is_pointer built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (27 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                                 ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_pointer.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_POINTER.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 155 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_pointer.C    |  51 ++++++++
 7 files changed, 141 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 8fbd67788d5..5d40e04f91c 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -61,6 +61,7 @@ struct cp_trait {
 "__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
 "__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
 "__is_pod", CPTK_IS_POD, 1, false
+"__is_pointer", CPTK_IS_POINTER, 1, false
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ad2c2a2d250..ab783b161c7 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 109, duplicates = 0 */
+/* maximum key range = 92, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116,  20, 116,  40,   5,  40,
-       50,   0,  55,  10, 116,   0, 116, 116,   5,  25,
-       30,   0,   5, 116,  10,  15,   5,   0,  25, 116,
-      116,  20, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
-      116, 116, 116, 116, 116, 116
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
+       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
+      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
+      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+      99, 99, 99, 99, 99, 99
     };
   unsigned int hval = len;
 
@@ -116,78 +116,78 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 57,
+      TOTAL_KEYWORDS = 58,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 115
+      MAX_HASH_VALUE = 98
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 73 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
+#line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
@@ -205,23 +205,27 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_array", CPTK_IS_ARRAY, 1, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 41 "../../gcc/cp/cp-trait.gperf"
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
@@ -236,22 +240,19 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4,  5,  6,  7,  8,  9, -1, -1, 10, 11, 12, 13, 14, 15,
-      16, -1, 17, 18, 19, 20, -1, 21, -1, 22, 23, -1, 24, -1,
+       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
       25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, -1, -1, -1, 42, 43,
-      44, -1, -1, -1, -1, 45, 46, -1, 47, 48, 49, -1, -1, -1,
-      -1, 50, 51, -1, 52, -1, 53, -1, -1, -1, -1, 54, -1, -1,
-      55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, 56
+      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
+      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
+      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      57
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 30/40] libstdc++: Optimize is_pointer trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (28 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
                                 ` (10 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..cd5ce45951f 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 31/40] c++: Implement __is_arithmetic built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (29 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                                 ` (9 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_arithmetic.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 184 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_arithmetic.C |  33 ++++
 7 files changed, 138 insertions(+), 91 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 5d40e04f91c..9050c36f105 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -39,6 +39,7 @@ struct cp_trait {
 "__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
 "__is_abstract", CPTK_IS_ABSTRACT, 1, false
 "__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false
 "__is_array", CPTK_IS_ARRAY, 1, false
 "__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
 "__is_base_of", CPTK_IS_BASE_OF, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index ab783b161c7..31fd5075f2d 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 92, duplicates = 0 */
+/* maximum key range = 97, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 20, 99, 40, 45, 40,
-       5,  0, 55, 10, 99,  0, 99, 99, 10, 25,
-      30,  0, 10, 99, 10, 15,  5,  0, 20, 99,
-      99, 10, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
-      99, 99, 99, 99, 99, 99
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
+        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
+       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
+      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+      104, 104, 104, 104, 104, 104
     };
   unsigned int hval = len;
 
@@ -116,130 +116,132 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 58,
+      TOTAL_KEYWORDS = 59,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 98
+      MAX_HASH_VALUE = 103
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 86 "../../gcc/cp/cp-trait.gperf"
+#line 87 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
+#line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 70 "../../gcc/cp/cp-trait.gperf"
+#line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 82 "../../gcc/cp/cp-trait.gperf"
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 50 "../../gcc/cp/cp-trait.gperf"
+#line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
+#line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
+#line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
+#line 69 "../../gcc/cp/cp-trait.gperf"
       {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
+#line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
+#line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
+#line 63 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 34 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
+#line 58 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+      {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
+#line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 42 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
       {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
+#line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
+#line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 58 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 57 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
+#line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
       {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 49 "../../gcc/cp/cp-trait.gperf"
+#line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
+#line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
+#line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
       {"__is_function", CPTK_IS_FUNCTION, 1, false}
     };
 
@@ -247,12 +249,12 @@ cp_trait_lookup::find (const char *str, size_t len)
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
        4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, -1, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      -1, -1, 36, 37, 38, 39, -1, 40, 41, 42, -1, -1, 43, 44,
-      45, -1, 46, -1, -1, 47, 48, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, 53, -1, 54, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      57
+      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
+      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
+      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
+      -1, -1, 57, -1, -1, 58
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (30 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                                 ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (31 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 34/40] libstdc++: Optimize is_compound " Ken Matsui
                                 ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 34/40] libstdc++: Optimize is_compound trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (32 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                                 ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 35/40] c++: Implement __is_unsigned built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (33 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                                 ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_unsigned.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_UNSIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 118 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_unsigned.C   |  47 +++++++++
 7 files changed, 120 insertions(+), 57 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 9050c36f105..90d05bca5c1 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -74,6 +74,7 @@ struct cp_trait {
 "__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
 "__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false
 "__is_union", CPTK_IS_UNION, 1, false
+"__is_unsigned", CPTK_IS_UNSIGNED, 1, false
 "__is_volatile", CPTK_IS_VOLATILE, 1, false
 "__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
 "__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 31fd5075f2d..75ab2b5edfa 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 97, duplicates = 0 */
+/* maximum key range = 129, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104,  20, 104,  45,  50,  40,
-        5,   0,  55,   0, 104,   0, 104, 104,  10,  15,
-       35,   0,  10, 104,  10,  15,   5,   0,  20, 104,
-      104,  20, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
-      104, 104, 104, 104, 104, 104
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
+       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
+       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
+      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+      136, 136, 136, 136, 136, 136
     };
   unsigned int hval = len;
 
@@ -116,46 +116,44 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 59,
+      TOTAL_KEYWORDS = 60,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 103
+      MAX_HASH_VALUE = 135
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 83 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
 #line 71 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 83 "../../gcc/cp/cp-trait.gperf"
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
 #line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
 #line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
@@ -165,11 +163,11 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
 #line 66 "../../gcc/cp/cp-trait.gperf"
       {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
+#line 79 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
@@ -180,7 +178,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
 #line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
@@ -207,6 +205,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
@@ -223,8 +223,8 @@ cp_trait_lookup::find (const char *str, size_t len)
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
 #line 67 "../../gcc/cp/cp-trait.gperf"
       {"__is_reference", CPTK_IS_REFERENCE, 1, false},
 #line 70 "../../gcc/cp/cp-trait.gperf"
@@ -242,19 +242,23 @@ cp_trait_lookup::find (const char *str, size_t len)
 #line 53 "../../gcc/cp/cp-trait.gperf"
       {"__is_final", CPTK_IS_FINAL, 1, false},
 #line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false}
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
-       4, -1,  5,  6,  7,  8,  9, -1, 10, 11, -1, 12, -1, 13,
-      14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, -1,
-      26, 27, 28, 29, -1, 30, 31, 32, 33, -1, 34, -1, 35, 36,
-      37, -1, 38, 39, 40, -1, -1, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, 49, -1, 50, 51, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
+       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
+      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
+      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
+      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
+      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
       -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58
+      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (34 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 37/40] c++: Implement __is_signed built-in trait Ken Matsui
                                 ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 37/40] c++: Implement __is_signed built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (35 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                                 ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_signed.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SIGNED.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_signed.
	* g++.dg/ext/is_signed.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 211 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_signed.C     |  47 +++++
 7 files changed, 165 insertions(+), 105 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index 90d05bca5c1..de0ba162e7a 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
 "__is_trivial", CPTK_IS_TRIVIAL, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 75ab2b5edfa..6d1078de2fe 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -54,7 +54,7 @@ struct cp_trait {
   short arity;
   bool type;
 };
-/* maximum key range = 129, duplicates = 0 */
+/* maximum key range = 119, duplicates = 0 */
 
 class cp_trait_lookup
 {
@@ -69,32 +69,32 @@ cp_trait_lookup::hash (const char *str, size_t len)
 {
   static const unsigned char asso_values[] =
     {
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136,  20, 136,  45,  35,  40,
-       60,   0,  55,   0, 136,   0, 136, 136,  10,  15,
-       35,   0,  10, 136,  10,  15,   5,  15,   0, 136,
-      136,  20, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
-      136, 136, 136, 136, 136, 136
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
+       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
+       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
+      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126, 126
     };
   unsigned int hval = len;
 
@@ -116,149 +116,150 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 60,
+      TOTAL_KEYWORDS = 61,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
-      MAX_HASH_VALUE = 135
+      MAX_HASH_VALUE = 125
     };
 
   static const struct cp_trait wordlist[] =
     {
-#line 88 "../../gcc/cp/cp-trait.gperf"
+#line 89 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 81 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 83 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 84 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 71 "../../gcc/cp/cp-trait.gperf"
+#line 72 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 84 "../../gcc/cp/cp-trait.gperf"
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
 #line 51 "../../gcc/cp/cp-trait.gperf"
       {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 65 "../../gcc/cp/cp-trait.gperf"
       {"__is_pointer", CPTK_IS_POINTER, 1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same", CPTK_IS_SAME, 2, false},
 #line 52 "../../gcc/cp/cp-trait.gperf"
       {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
+#line 77 "../../gcc/cp/cp-trait.gperf"
       {"__is_union", CPTK_IS_UNION, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 30 "../../gcc/cp/cp-trait.gperf"
+      {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
 #line 69 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 56 "../../gcc/cp/cp-trait.gperf"
-      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+      {"__is_signed", CPTK_IS_SIGNED, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
+#line 80 "../../gcc/cp/cp-trait.gperf"
       {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 33 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 68 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same", CPTK_IS_SAME, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
 #line 31 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 30 "../../gcc/cp/cp-trait.gperf"
-      {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 39 "../../gcc/cp/cp-trait.gperf"
       {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
 #line 32 "../../gcc/cp/cp-trait.gperf"
       {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
-#line 36 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
-#line 55 "../../gcc/cp/cp-trait.gperf"
-      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
-#line 37 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
-#line 35 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
 #line 45 "../../gcc/cp/cp-trait.gperf"
       {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
 #line 60 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
 #line 62 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
 #line 61 "../../gcc/cp/cp-trait.gperf"
       {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pod", CPTK_IS_POD, 1, false},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
 #line 46 "../../gcc/cp/cp-trait.gperf"
       {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 40 "../../gcc/cp/cp-trait.gperf"
-      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
-#line 44 "../../gcc/cp/cp-trait.gperf"
-      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 64 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pod", CPTK_IS_POD, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 38 "../../gcc/cp/cp-trait.gperf"
       {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+      {"__is_class", CPTK_IS_CLASS, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 47 "../../gcc/cp/cp-trait.gperf"
-      {"__is_class", CPTK_IS_CLASS, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
+#line 88 "../../gcc/cp/cp-trait.gperf"
       {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
     };
 
   static const signed char lookup[] =
     {
       -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7, -1,  8,  9, 10, 11, -1, 12,
-      13, 14, 15, 16, 17, 18, -1, 19, 20, 21, 22, 23, 24, -1,
-      25, 26, 27, 28, -1, 29, 30, 31, 32, -1, 33, -1, 34, 35,
-      36, -1, 37, 38, 39, -1, 40, 41, 42, 43, 44, -1, 45, -1,
-      46, -1, -1, 47, -1, 48, -1, -1, 49, 50, 51, -1, -1, -1,
-      -1, 52, -1, -1, -1, -1, 53, 54, -1, 55, -1, 56, -1, -1,
-      -1, -1, 57, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, 59
+       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
+      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
+      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
+      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
+      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
+      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
+      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 38/40] libstdc++: Optimize is_signed trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (36 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 37/40] c++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
                                 ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 39/40] c++: Implement __is_scalar built-in trait
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (37 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-13 22:37               ` [PATCH v19 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_scalar.
	* cp-trait.gperf: Reflect cp-trait.def change.
	* cp-trait.h: Likewise.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_SCALAR.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   3 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/cp-trait.gperf                    |   1 +
 gcc/cp/cp-trait.h                        | 186 ++++++++++++-----------
 gcc/cp/semantics.cc                      |   4 +
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_scalar.C     |  31 ++++
 7 files changed, 137 insertions(+), 92 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
index de0ba162e7a..ef51c713c58 100644
--- a/gcc/cp/cp-trait.gperf
+++ b/gcc/cp/cp-trait.gperf
@@ -66,6 +66,7 @@ struct cp_trait {
 "__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
 "__is_reference", CPTK_IS_REFERENCE, 1, false
 "__is_same", CPTK_IS_SAME, 2, false
+"__is_scalar", CPTK_IS_SCALAR, 1, false
 "__is_signed", CPTK_IS_SIGNED, 1, false
 "__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false
 "__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
index 6d1078de2fe..8c68af420f9 100644
--- a/gcc/cp/cp-trait.h
+++ b/gcc/cp/cp-trait.h
@@ -78,10 +78,10 @@ cp_trait_lookup::hash (const char *str, size_t len)
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
-      126, 126, 126, 126, 126,  20, 126,  40,  45,  50,
-       55,   0,   5,  15, 126,   0, 126, 126,  35,  10,
-       35,   0,  10, 126,  30,   5,   5,  16,  30, 126,
-      126,  10, 126, 126, 126, 126, 126, 126, 126, 126,
+      126, 126, 126, 126, 126,  40, 126,  25,  21,  50,
+        0,   0,  30,  10, 126,   0, 126, 126,  25,   5,
+       50,   0,  61, 126,  10,  10,   5,   0,  15, 126,
+      126,   5, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
       126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
@@ -116,7 +116,7 @@ cp_trait_lookup::find (const char *str, size_t len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 61,
+      TOTAL_KEYWORDS = 62,
       MIN_WORD_LENGTH = 7,
       MAX_WORD_LENGTH = 37,
       MIN_HASH_VALUE = 7,
@@ -125,141 +125,143 @@ cp_trait_lookup::find (const char *str, size_t len)
 
   static const struct cp_trait wordlist[] =
     {
-#line 89 "../../gcc/cp/cp-trait.gperf"
+#line 90 "../../gcc/cp/cp-trait.gperf"
       {"__bases", CPTK_BASES, 1, true},
-#line 82 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+      {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 78 "../../gcc/cp/cp-trait.gperf"
+      {"__is_union", CPTK_IS_UNION, 1, false},
 #line 83 "../../gcc/cp/cp-trait.gperf"
-      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
 #line 84 "../../gcc/cp/cp-trait.gperf"
+      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 89 "../../gcc/cp/cp-trait.gperf"
+      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 85 "../../gcc/cp/cp-trait.gperf"
       {"__remove_pointer", CPTK_REMOVE_POINTER, 1, true},
-#line 72 "../../gcc/cp/cp-trait.gperf"
+#line 73 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
-#line 85 "../../gcc/cp/cp-trait.gperf"
+#line 86 "../../gcc/cp/cp-trait.gperf"
       {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
-#line 90 "../../gcc/cp/cp-trait.gperf"
+#line 91 "../../gcc/cp/cp-trait.gperf"
       {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
-#line 51 "../../gcc/cp/cp-trait.gperf"
-      {"__is_empty", CPTK_IS_EMPTY, 1, false},
-#line 70 "../../gcc/cp/cp-trait.gperf"
-      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
-#line 65 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer", CPTK_IS_POINTER, 1, false},
+#line 79 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
 #line 68 "../../gcc/cp/cp-trait.gperf"
       {"__is_same", CPTK_IS_SAME, 2, false},
-#line 52 "../../gcc/cp/cp-trait.gperf"
-      {"__is_enum", CPTK_IS_ENUM, 1, false},
-#line 77 "../../gcc/cp/cp-trait.gperf"
-      {"__is_union", CPTK_IS_UNION, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scoped_enum", CPTK_IS_SCOPED_ENUM, 1, false},
 #line 30 "../../gcc/cp/cp-trait.gperf"
       {"__is_same_as", CPTK_IS_SAME, 2, false},
-#line 75 "../../gcc/cp/cp-trait.gperf"
+#line 76 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
-#line 86 "../../gcc/cp/cp-trait.gperf"
-      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
-#line 73 "../../gcc/cp/cp-trait.gperf"
+#line 59 "../../gcc/cp/cp-trait.gperf"
+      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
-#line 69 "../../gcc/cp/cp-trait.gperf"
+#line 70 "../../gcc/cp/cp-trait.gperf"
       {"__is_signed", CPTK_IS_SIGNED, 1, false},
-#line 74 "../../gcc/cp/cp-trait.gperf"
+#line 75 "../../gcc/cp/cp-trait.gperf"
       {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
-#line 78 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unsigned", CPTK_IS_UNSIGNED, 1, false},
-#line 81 "../../gcc/cp/cp-trait.gperf"
+#line 82 "../../gcc/cp/cp-trait.gperf"
       {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
-#line 80 "../../gcc/cp/cp-trait.gperf"
-      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
-#line 33 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
-#line 59 "../../gcc/cp/cp-trait.gperf"
-      {"__is_member_pointer", CPTK_IS_MEMBER_POINTER, 1, false},
-#line 31 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
-#line 39 "../../gcc/cp/cp-trait.gperf"
-      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
-#line 32 "../../gcc/cp/cp-trait.gperf"
-      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 58 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_object_pointer", CPTK_IS_MEMBER_OBJECT_POINTER, 1, false},
-#line 63 "../../gcc/cp/cp-trait.gperf"
-      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 81 "../../gcc/cp/cp-trait.gperf"
+      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
 #line 57 "../../gcc/cp/cp-trait.gperf"
       {"__is_member_function_pointer", CPTK_IS_MEMBER_FUNCTION_POINTER, 1, false},
-#line 67 "../../gcc/cp/cp-trait.gperf"
-      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
-#line 53 "../../gcc/cp/cp-trait.gperf"
-      {"__is_final", CPTK_IS_FINAL, 1, false},
-#line 87 "../../gcc/cp/cp-trait.gperf"
-      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
-#line 54 "../../gcc/cp/cp-trait.gperf"
-      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
 #line 42 "../../gcc/cp/cp-trait.gperf"
       {"__is_arithmetic", CPTK_IS_ARITHMETIC, 1, false},
+#line 77 "../../gcc/cp/cp-trait.gperf"
+      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
+#line 88 "../../gcc/cp/cp-trait.gperf"
+      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+      {"__is_array", CPTK_IS_ARRAY, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+      {"__is_scalar", CPTK_IS_SCALAR, 1, false},
 #line 56 "../../gcc/cp/cp-trait.gperf"
       {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
 #line 40 "../../gcc/cp/cp-trait.gperf"
       {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
 #line 44 "../../gcc/cp/cp-trait.gperf"
       {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
-#line 66 "../../gcc/cp/cp-trait.gperf"
-      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
-#line 45 "../../gcc/cp/cp-trait.gperf"
-      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
-#line 60 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
-#line 62 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
-#line 71 "../../gcc/cp/cp-trait.gperf"
-      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
-#line 61 "../../gcc/cp/cp-trait.gperf"
-      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 55 "../../gcc/cp/cp-trait.gperf"
       {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 80 "../../gcc/cp/cp-trait.gperf"
+      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+      {"__is_reference", CPTK_IS_REFERENCE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
 #line 36 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
-#line 41 "../../gcc/cp/cp-trait.gperf"
-      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
-#line 34 "../../gcc/cp/cp-trait.gperf"
-      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
 #line 64 "../../gcc/cp/cp-trait.gperf"
       {"__is_pod", CPTK_IS_POD, 1, false},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+      {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer", CPTK_IS_POINTER, 1, false},
 #line 37 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
 #line 35 "../../gcc/cp/cp-trait.gperf"
       {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
-#line 79 "../../gcc/cp/cp-trait.gperf"
-      {"__is_volatile", CPTK_IS_VOLATILE, 1, false},
-#line 46 "../../gcc/cp/cp-trait.gperf"
-      {"__is_bounded_array", CPTK_IS_BOUNDED_ARRAY, 1, false},
-#line 43 "../../gcc/cp/cp-trait.gperf"
-      {"__is_array", CPTK_IS_ARRAY, 1, false},
-#line 76 "../../gcc/cp/cp-trait.gperf"
-      {"__is_unbounded_array", CPTK_IS_UNBOUNDED_ARRAY, 1, false},
-#line 38 "../../gcc/cp/cp-trait.gperf"
-      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false},
-#line 48 "../../gcc/cp/cp-trait.gperf"
-      {"__is_const", CPTK_IS_CONST, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 87 "../../gcc/cp/cp-trait.gperf"
+      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
 #line 47 "../../gcc/cp/cp-trait.gperf"
       {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+      {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+      {"__is_function", CPTK_IS_FUNCTION, 1, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+      {"__is_const", CPTK_IS_CONST, 1, false},
 #line 50 "../../gcc/cp/cp-trait.gperf"
       {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
 #line 49 "../../gcc/cp/cp-trait.gperf"
       {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
-#line 88 "../../gcc/cp/cp-trait.gperf"
-      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false}
+#line 38 "../../gcc/cp/cp-trait.gperf"
+      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
     };
 
   static const signed char lookup[] =
     {
-      -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1,  1, -1, -1,
-       2, -1,  3,  4,  5,  6,  7,  8,  9, -1, 10, 11, 12, 13,
-      14, 15, 16, 17, -1, 18, 19, 20, -1, 21, 22, 23, 24, -1,
-      -1, -1, 25, 26, 27, 28, 29, 30, 31, -1, 32, 33, -1, 34,
-      -1, 35, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-      47, -1, -1, 48, 49, 50, -1, -1, 51, 52, 53, 54, -1, -1,
-      -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, 56, -1, -1,
-      -1, -1, 57, 58, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1,
-      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60
+      -1, -1, -1, -1, -1, -1, -1,  0, -1,  1,  2,  3, -1, -1,
+       4,  5,  6,  7,  8,  9, -1, -1, -1, 10, 11, -1, 12, 13,
+      14, 15, 16, 17, -1, 18, -1, 19, 20, 21, 22, 23, 24, 25,
+      26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
+      -1, -1, 38, -1, 39, -1, -1, -1, 40, 41, -1, -1, 42, 43,
+      44, 45, -1, 46, 47, 48, -1, -1, 49, 50, 51, 52, -1, -1,
+      -1, 53, -1, -1, -1, -1, 54, -1, -1, 55, -1, -1, -1, -1,
+      56, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, 58, -1,
+      -1, -1, -1, -1, 59, -1, 60, -1, -1, -1, -1, -1, -1, 61
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v19 40/40] libstdc++: Optimize is_scalar trait performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (38 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-13 22:37               ` Ken Matsui
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-13 22:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-13 22:37               ` [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
@ 2023-10-15 20:43                 ` Patrick Palka
  2023-10-15 21:04                   ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-15 20:43 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Patrick Palka, jason

On Fri, 13 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses gperf to look up the specific trait.  Rather than holding
> traits as keywords, we set all trait identifiers as cik_trait, which is a new
> cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.

Awesome!  It's great we won't have to rename any existing identifiers in
libstdc++ with this approach.

I think this patch looks perfect, assuming we want to stick with the gperf
approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
field which is currently only used for operator name identifiers to
optimize looking up operator information.  Could we reuse this field for
IDENTIFIER_TRAIT_P identifiers as well in order to store their
corresponding cp_trait_kind?  If so then I think we wouldn't need to use
gperf for the built-in traits at all, since the mapping from identifier
to cp_trait_kind would be implicit in each IDENTIFIER node, which would
perhaps be a nice simplification (and just as fast if not faster than gperf)?

> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Remove all mappings of
> 	built-in traits.
> 	* c-common.h (enum rid): Remove all RID values for built-in traits.
> 
> gcc/cp/ChangeLog:
> 
> 	* Make-lang.in: Add targets to generate cp-trait.gperf and
> 	cp-trait.h.
> 	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
> 	cases for built-in traits.  Check for built-in traits via
> 	the new cik_trait identifier.
> 	* cp-tree.h (cik_reserved_for_udlit): Rename to ...
> 	(cik_trait): ... this.
> 	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> 	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> 	* lex.cc (init_cp_traits): New function to set cik_trait for all
> 	built-in trait identifiers.
> 	(cxx_init): Call init_cp_traits function.
> 	* parser.cc (cp_lexer_lookup_trait): New function to look up a
> 	built-in trait from a token by gperf.
> 	(cp_lexer_lookup_trait_expr): Likewise, look up an
> 	expression-yielding built-in trait.
> 	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> 	built-in trait.
> 	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> 	for built-in traits.
> 	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
> 	type-yielding built-in traits.
> 	(cp_parser_primary_expression): Remove all RID value cases for
> 	built-in traits.  Handle expression-yielding built-in traits.
> 	(cp_parser_trait): Handle cp_trait instead of enum rid.
> 	(cp_parser_simple_type_specifier): Remove all RID value cases
> 	for built-in traits.  Handle type-yielding built-in traits.
> 	* cp-trait-head.in: New file.
> 	* cp-trait.gperf: New file.
> 	* cp-trait.h: New file.
> 
> Co-authored-by: Patrick Palka <ppalka@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |   7 --
>  gcc/c-family/c-common.h   |   5 -
>  gcc/cp/Make-lang.in       |  26 ++++
>  gcc/cp/cp-objcp-common.cc |   8 +-
>  gcc/cp/cp-trait-head.in   |  30 +++++
>  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
>  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
>  gcc/cp/cp-tree.h          |  14 ++-
>  gcc/cp/lex.cc             |  19 +++
>  gcc/cp/parser.cc          | 132 ++++++++++++--------
>  10 files changed, 492 insertions(+), 70 deletions(-)
>  create mode 100644 gcc/cp/cp-trait-head.in
>  create mode 100644 gcc/cp/cp-trait.gperf
>  create mode 100644 gcc/cp/cp-trait.h
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",		RID_WCHAR,	D_CXXONLY },
>    { "while",		RID_WHILE,	0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,		RID_##CODE,	D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
> -
>    /* C++ transactional memory.  */
>    { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>    { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>  
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..a67d1c3e9f3 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
>  # - the compiler proper (eg: cc1plus)
>  # - define the names for selecting the language in LANGUAGES.
>  
> +AWK = @AWK@
> +
>  # Actual names to use when installing a native compiler.
>  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
>  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,30 @@ endif
>  # This is the file that depends on the generated header file.
>  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>  
> +# We always need the dependency on the .gperf file
> +# because it itself is generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> +	gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> +		$(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf file itself is generated from
> +# cp-trait-head.in and cp-trait.def files.
> +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> +	cat $< > $@
> +	$(AWK) -F', *' '/^DEFTRAIT_/ { \
> +		type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> +		gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> +		gsub(/\)/, "", $$3); \
> +		print $$2", CPTK_" $$1", "$$3", "type; \
> +	}' $(srcdir)/cp/cp-trait.def >> $@
> +
> +# This is the file that depends on the generated header file.
> +cp/parser.o: $(srcdir)/cp/cp-trait.h
> +
>  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
>  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
>  	}
>      }
>  
> +  /* Check for built-in traits.  */
> +  if (IDENTIFIER_TRAIT_P (id))
> +    return true;
> +
>    /* Also detect common reserved C++ words that aren't strictly built-in
>       functions.  */
>    switch (C_RID_CODE (id))
> @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> new file mode 100644
> index 00000000000..9357eea1238
> --- /dev/null
> +++ b/gcc/cp/cp-trait-head.in
> @@ -0,0 +1,30 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> new file mode 100644
> index 00000000000..47e3c1af499
> --- /dev/null
> +++ b/gcc/cp/cp-trait.gperf
> @@ -0,0 +1,74 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +%}
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> +"__is_class", CPTK_IS_CLASS, 1, false
> +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> +"__is_empty", CPTK_IS_EMPTY, 1, false
> +"__is_enum", CPTK_IS_ENUM, 1, false
> +"__is_final", CPTK_IS_FINAL, 1, false
> +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> +"__is_pod", CPTK_IS_POD, 1, false
> +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> +"__is_same", CPTK_IS_SAME, 2, false
> +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> +"__is_union", CPTK_IS_UNION, 1, false
> +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> +"__remove_cv", CPTK_REMOVE_CV, 1, true
> +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> +"__bases", CPTK_BASES, 1, true
> +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> new file mode 100644
> index 00000000000..97ba8492d15
> --- /dev/null
> +++ b/gcc/cp/cp-trait.h
> @@ -0,0 +1,247 @@
> +/* C++ code produced by gperf version 3.1 */
> +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> +
> +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> +/* The character set is not based on ISO-646.  */
> +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> +#endif
> +
> +#line 4 "../../gcc/cp/cp-trait.gperf"
> +
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +#line 23 "../../gcc/cp/cp-trait.gperf"
> +struct cp_trait {
> +  const char *name;
> +  enum cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +/* maximum key range = 79, duplicates = 0 */
> +
> +class cp_trait_lookup
> +{
> +private:
> +  static inline unsigned int hash (const char *str, size_t len);
> +public:
> +  static const struct cp_trait *find (const char *str, size_t len);
> +};
> +
> +inline unsigned int
> +cp_trait_lookup::hash (const char *str, size_t len)
> +{
> +  static const unsigned char asso_values[] =
> +    {
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> +      86, 86, 86, 86, 86, 86
> +    };
> +  unsigned int hval = len;
> +
> +  switch (hval)
> +    {
> +      default:
> +        hval += asso_values[static_cast<unsigned char>(str[7])];
> +      /*FALLTHROUGH*/
> +      case 7:
> +        break;
> +    }
> +  return hval;
> +}
> +
> +const struct cp_trait *
> +cp_trait_lookup::find (const char *str, size_t len)
> +{
> +  enum
> +    {
> +      TOTAL_KEYWORDS = 45,
> +      MIN_WORD_LENGTH = 7,
> +      MAX_WORD_LENGTH = 37,
> +      MIN_HASH_VALUE = 7,
> +      MAX_HASH_VALUE = 85
> +    };
> +
> +  static const struct cp_trait wordlist[] =
> +    {
> +#line 73 "../../gcc/cp/cp-trait.gperf"
> +      {"__bases", CPTK_BASES, 1, true},
> +#line 56 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pod", CPTK_IS_POD, 1, false},
> +#line 48 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> +#line 64 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_union", CPTK_IS_UNION, 1, false},
> +#line 44 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_class", CPTK_IS_CLASS, 1, false},
> +#line 60 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> +#line 41 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> +#line 72 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> +#line 43 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> +#line 40 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> +#line 58 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same", CPTK_IS_SAME, 2, false},
> +#line 42 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> +#line 59 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> +#line 30 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> +#line 63 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> +#line 39 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> +#line 61 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> +#line 57 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> +#line 71 "../../gcc/cp/cp-trait.gperf"
> +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> +#line 62 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> +#line 74 "../../gcc/cp/cp-trait.gperf"
> +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> +#line 51 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> +#line 33 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> +#line 31 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> +#line 55 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> +#line 52 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> +#line 54 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> +#line 32 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> +#line 53 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> +#line 50 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> +#line 67 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> +#line 36 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> +#line 68 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> +#line 34 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> +#line 69 "../../gcc/cp/cp-trait.gperf"
> +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> +#line 37 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> +#line 35 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> +#line 49 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_final", CPTK_IS_FINAL, 1, false},
> +#line 47 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> +#line 46 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> +#line 45 "../../gcc/cp/cp-trait.gperf"
> +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> +#line 66 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> +#line 65 "../../gcc/cp/cp-trait.gperf"
> +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> +#line 70 "../../gcc/cp/cp-trait.gperf"
> +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> +#line 38 "../../gcc/cp/cp-trait.gperf"
> +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> +    };
> +
> +  static const signed char lookup[] =
> +    {
> +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> +      -1, 44
> +    };
> +
> +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> +    {
> +      unsigned int key = hash (str, len);
> +
> +      if (key <= MAX_HASH_VALUE)
> +        {
> +          int index = lookup[key];
> +
> +          if (index >= 0)
> +            {
> +              const char *s = wordlist[index].name;
> +
> +              if (*str == *s && !strcmp (str + 1, s + 1))
> +                return &wordlist[index];
> +            }
> +        }
> +    }
> +  return 0;
> +}
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 6e34952da99..62e134886fb 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
>    cik_simple_op = 4,	/* Non-assignment operator name.  */
>    cik_assign_op = 5,	/* An assignment operator name.  */
>    cik_conv_op = 6,	/* Conversion operator name.  */
> -  cik_reserved_for_udlit = 7,	/* Not yet in use  */
> +  cik_trait = 7,	/* Built-in trait name.  */
>    cik_max
>  };
>  
> @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
>      & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is for any operator name (including
> -   conversions).  Value 4, 5, 6 or 7.  */
> +   conversions).  Value 4, 5, or 6.  */
>  #define IDENTIFIER_ANY_OP_P(NODE)		\
> -  (IDENTIFIER_KIND_BIT_2 (NODE))
> +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
>  
>  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
>  #define IDENTIFIER_OVL_OP_P(NODE)		\
> @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
>     & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is the name of a type-conversion
> -   operator.  Value 7.  */
> +   operator.  Value 6.  */
>  #define IDENTIFIER_CONV_OP_P(NODE)		\
>    (IDENTIFIER_ANY_OP_P (NODE)			\
>     & IDENTIFIER_KIND_BIT_1 (NODE)		\
>     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
>  
> +/* True if this identifier is the name of a built-in trait.  */
> +#define IDENTIFIER_TRAIT_P(NODE)		\
> +  (IDENTIFIER_KIND_BIT_0 (NODE)			\
> +   && IDENTIFIER_KIND_BIT_1 (NODE)		\
> +   && IDENTIFIER_KIND_BIT_2 (NODE))
> +
>  /* True if this identifier is a new or delete operator.  */
>  #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
>    (IDENTIFIER_OVL_OP_P (NODE)			\
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..f6e1f6a4075 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>  
>  static int interface_strcmp (const char *);
> +static void init_cp_traits (void);
>  static void init_cp_pragma (void);
>  
>  static tree parse_strconst_pragma (const char *, int);
> @@ -283,6 +284,23 @@ init_reswords (void)
>      }
>  }
>  
> +/* Initialize the C++ traits.  */
> +static void
> +init_cp_traits (void)
> +{
> +  tree id;
> +
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> +  id = get_identifier (NAME); \
> +  set_identifier_kind (id, cik_trait);
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT
> +
> +  /* An alias for __is_same.  */
> +  id = get_identifier ("__is_same_as");
> +  set_identifier_kind (id, cik_trait);
> +}
> +
>  static void
>  init_cp_pragma (void)
>  {
> @@ -324,6 +342,7 @@ cxx_init (void)
>    input_location = BUILTINS_LOCATION;
>  
>    init_reswords ();
> +  init_cp_traits ();
>    init_tree ();
>    init_cp_semantics ();
>    init_operators ();
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index f3abae716fe..39952893ffa 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "contracts.h"
>  #include "bitmap.h"
>  #include "builtins.h"
> +#include "cp-trait.h"
>  
>  \f
>  /* The lexer.  */
> @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
> +static const cp_trait *cp_lexer_lookup_trait
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_expr
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_type
> +  (const cp_token *);
>  
>  static cp_token_cache *cp_token_cache_new
>    (cp_token *, cp_token *);
> @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      case RID_CONSTEVAL:
>        return true;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      return true;
> -
>      default:
>        if (keyword >= RID_FIRST_INT_N
>  	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      }
>  }
>  
> +/* Look ups the corresponding built-in trait if a given token is
> +   a built-in trait.  Otherwise, returns nullptr.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait (const cp_token *token)
> +{
> +  tree id = token->u.value;
> +
> +  if (token->type == CPP_NAME
> +      && TREE_CODE (id) == IDENTIFIER_NODE
> +      && IDENTIFIER_TRAIT_P (id))
> +    {
> +      const char *id_str = IDENTIFIER_POINTER (id);
> +      const int id_len = IDENTIFIER_LENGTH (id);
> +      return cp_trait_lookup::find (id_str, id_len);
> +    }
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is an expression-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_expr (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && !trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is a type-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_type (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
>  /* Return true if the next token is a keyword for a decl-specifier.  */
>  
>  static bool
> @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
>    cp_token *token;
>  
>    token = cp_lexer_peek_token (lexer);
> +  if (cp_lexer_lookup_trait_type (token))
> +    return true;
>    return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
>  
> @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, const cp_trait *);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_OFFSETOF:
>  	  return cp_parser_builtin_offsetof (parser);
>  
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -	case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -	  return cp_parser_trait (parser, token->keyword);
> -
>  	// C++ concepts
>  	case RID_REQUIRES:
>  	  return cp_parser_requires_expression (parser);
> @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
>  	 `::' as the beginning of a qualified-id, or the "operator"
>  	 keyword.  */
>      case CPP_NAME:
> +      {
> +	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> +	if (trait)
> +	  return cp_parser_trait (parser, trait);
> +      }
> +      /* FALLTHRU */
>      case CPP_SCOPE:
>      case CPP_TEMPLATE_ID:
>      case CPP_NESTED_NAME_SPECIFIER:
> @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>  
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
>  {
> -  cp_trait_kind kind;
>    tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> -
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:			 \
> -      kind = CPTK_##CODE;		 \
> -      binary = (ARITY == 2);		 \
> -      variadic = (ARITY == -1);		 \
> -      type = (TCC == tcc_type);		 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  const bool binary = (trait->arity == 2);
> +  const bool variadic = (trait->arity == -1);
>  
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    cp_lexer_consume_token (parser->lexer);
>  
>    matching_parens parens;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      cp_parser_require (parser, CPP_LESS, RT_LESS);
>    else
>      parens.require_open (parser);
>  
> -  if (kind == CPTK_IS_DEDUCIBLE)
> +  if (trait->kind == CPTK_IS_DEDUCIBLE)
>      {
>        const cp_token* token = cp_lexer_peek_token (parser->lexer);
>        type1 = cp_parser_id_expression (parser,
> @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  				       /*optional_p=*/false);
>        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
>      }
> -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* __type_pack_element takes an expression as its first argument and uses
>         template-id syntax instead of function call syntax (for consistency
>         with Clang).  We special case these properties of __type_pack_element
> @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    if (type1 == error_mark_node)
>      return error_mark_node;
>  
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      {
>        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
>        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>      }
>  
>    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* cp_parser_enclosed_template_argument_list above already took care
>         of parsing the closing '>'.  */;
>    else
> @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  
>    /* Complete the trait expression, which may mean either processing
>       the trait expr now or saving it for template instantiation.  */
> -  switch (kind)
> +  switch (trait->kind)
>      {
>      case CPTK_BASES:
>        return cp_expr (finish_bases (type1, false), trait_loc);
>      case CPTK_DIRECT_BASES:
>        return cp_expr (finish_bases (type1, true), trait_loc);
>      default:
> -      if (type)
> -	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> +      if (trait->type)
> +	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
>        else
> -	return finish_trait_expr (trait_loc, kind, type1, type2);
> +	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
>      }
>  }
>  
> @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>  
>        return type;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    default:
> +      break;
> +    }
> +
> +  /* If token is a type-yielding built-in traits, parse it.  */
> +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> +  if (trait)
> +    {
> +      type = cp_parser_trait (parser, trait);
>        if (decl_specs)
>  	cp_parser_set_decl_spec_type (decl_specs, type,
>  				      token,
>  				      /*type_definition_p=*/false);
>  
>        return type;
> -
> -    default:
> -      break;
>      }
>  
>    /* If token is an already-parsed decltype not followed by ::,
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-15 20:43                 ` Patrick Palka
@ 2023-10-15 21:04                   ` Ken Matsui
  2023-10-15 21:50                     ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-15 21:04 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++, jason

On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Fri, 13 Oct 2023, Ken Matsui wrote:
>
> > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > once in a C++ translation unit, this patch removes all RID values for built-in
> > traits and uses gperf to look up the specific trait.  Rather than holding
> > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > identifier so that we accept the use of non-function-like built-in trait
> > identifiers.
>
> Awesome!  It's great we won't have to rename any existing identifiers in
> libstdc++ with this approach.
>
> I think this patch looks perfect, assuming we want to stick with the gperf
> approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> field which is currently only used for operator name identifiers to
> optimize looking up operator information.  Could we reuse this field for
> IDENTIFIER_TRAIT_P identifiers as well in order to store their
> corresponding cp_trait_kind?  If so then I think we wouldn't need to use
> gperf for the built-in traits at all, since the mapping from identifier
> to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> perhaps be a nice simplification (and just as fast if not faster than gperf)?
>

Thank you! I think this way decreases the size of the compiler even if
we do not see speed improvements. Since IDENTIFIER_CP_INDEX
(base.u.bits.address_space) is an unsigned char (addr_space_t), we can
have only up to 255 traits. Is this acceptable?

> >
> > gcc/c-family/ChangeLog:
> >
> >       * c-common.cc (c_common_reswords): Remove all mappings of
> >       built-in traits.
> >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> >
> > gcc/cp/ChangeLog:
> >
> >       * Make-lang.in: Add targets to generate cp-trait.gperf and
> >       cp-trait.h.
> >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> >       cases for built-in traits.  Check for built-in traits via
> >       the new cik_trait identifier.
> >       * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> >       (cik_trait): ... this.
> >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> >       built-in trait identifiers.
> >       (cxx_init): Call init_cp_traits function.
> >       * parser.cc (cp_lexer_lookup_trait): New function to look up a
> >       built-in trait from a token by gperf.
> >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> >       expression-yielding built-in trait.
> >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> >       built-in trait.
> >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> >       for built-in traits.
> >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> >       type-yielding built-in traits.
> >       (cp_parser_primary_expression): Remove all RID value cases for
> >       built-in traits.  Handle expression-yielding built-in traits.
> >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> >       (cp_parser_simple_type_specifier): Remove all RID value cases
> >       for built-in traits.  Handle type-yielding built-in traits.
> >       * cp-trait-head.in: New file.
> >       * cp-trait.gperf: New file.
> >       * cp-trait.h: New file.
> >
> > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/c-family/c-common.cc  |   7 --
> >  gcc/c-family/c-common.h   |   5 -
> >  gcc/cp/Make-lang.in       |  26 ++++
> >  gcc/cp/cp-objcp-common.cc |   8 +-
> >  gcc/cp/cp-trait-head.in   |  30 +++++
> >  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
> >  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
> >  gcc/cp/cp-tree.h          |  14 ++-
> >  gcc/cp/lex.cc             |  19 +++
> >  gcc/cp/parser.cc          | 132 ++++++++++++--------
> >  10 files changed, 492 insertions(+), 70 deletions(-)
> >  create mode 100644 gcc/cp/cp-trait-head.in
> >  create mode 100644 gcc/cp/cp-trait.gperf
> >  create mode 100644 gcc/cp/cp-trait.h
> >
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index f044db5b797..21fd333ef57 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
> > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> >    { "while",         RID_WHILE,      0 },
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -  /* An alias for __is_same.  */
> > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > -
> >    /* C++ transactional memory.  */
> >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 1fdba7ef3ea..051a442e0f4 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -168,11 +168,6 @@ enum rid
> >    RID_BUILTIN_LAUNDER,
> >    RID_BUILTIN_BIT_CAST,
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  RID_##CODE,
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -
> >    /* C++11 */
> >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> >
> > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > index 2727fb7f8cc..a67d1c3e9f3 100644
> > --- a/gcc/cp/Make-lang.in
> > +++ b/gcc/cp/Make-lang.in
> > @@ -34,6 +34,8 @@
> >  # - the compiler proper (eg: cc1plus)
> >  # - define the names for selecting the language in LANGUAGES.
> >
> > +AWK = @AWK@
> > +
> >  # Actual names to use when installing a native compiler.
> >  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> >  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > @@ -186,6 +188,30 @@ endif
> >  # This is the file that depends on the generated header file.
> >  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> >
> > +# We always need the dependency on the .gperf file
> > +# because it itself is generated.
> > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > +else
> > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > +endif
> > +     gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > +             $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > +
> > +# The cp-trait.gperf file itself is generated from
> > +# cp-trait-head.in and cp-trait.def files.
> > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > +     cat $< > $@
> > +     $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > +             type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > +             gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > +             gsub(/\)/, "", $$3); \
> > +             print $$2", CPTK_" $$1", "$$3", "type; \
> > +     }' $(srcdir)/cp/cp-trait.def >> $@
> > +
> > +# This is the file that depends on the generated header file.
> > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > +
> >  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> >  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> >
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 93b027b80ce..b1adacfec07 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> >       }
> >      }
> >
> > +  /* Check for built-in traits.  */
> > +  if (IDENTIFIER_TRAIT_P (id))
> > +    return true;
> > +
> >    /* Also detect common reserved C++ words that aren't strictly built-in
> >       functions.  */
> >    switch (C_RID_CODE (id))
> > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> >      case RID_BUILTIN_ASSOC_BARRIER:
> >      case RID_BUILTIN_BIT_CAST:
> >      case RID_OFFSETOF:
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> >        return true;
> >      default:
> >        break;
> > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > new file mode 100644
> > index 00000000000..9357eea1238
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait-head.in
> > @@ -0,0 +1,30 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +%}
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > new file mode 100644
> > index 00000000000..47e3c1af499
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.gperf
> > @@ -0,0 +1,74 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +%}
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > +"__is_class", CPTK_IS_CLASS, 1, false
> > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > +"__is_enum", CPTK_IS_ENUM, 1, false
> > +"__is_final", CPTK_IS_FINAL, 1, false
> > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > +"__is_pod", CPTK_IS_POD, 1, false
> > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > +"__is_same", CPTK_IS_SAME, 2, false
> > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > +"__is_union", CPTK_IS_UNION, 1, false
> > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > +"__bases", CPTK_BASES, 1, true
> > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > new file mode 100644
> > index 00000000000..97ba8492d15
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.h
> > @@ -0,0 +1,247 @@
> > +/* C++ code produced by gperf version 3.1 */
> > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> > +
> > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > +/* The character set is not based on ISO-646.  */
> > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > +#endif
> > +
> > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > +
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > +struct cp_trait {
> > +  const char *name;
> > +  enum cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +/* maximum key range = 79, duplicates = 0 */
> > +
> > +class cp_trait_lookup
> > +{
> > +private:
> > +  static inline unsigned int hash (const char *str, size_t len);
> > +public:
> > +  static const struct cp_trait *find (const char *str, size_t len);
> > +};
> > +
> > +inline unsigned int
> > +cp_trait_lookup::hash (const char *str, size_t len)
> > +{
> > +  static const unsigned char asso_values[] =
> > +    {
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> > +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> > +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> > +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > +      86, 86, 86, 86, 86, 86
> > +    };
> > +  unsigned int hval = len;
> > +
> > +  switch (hval)
> > +    {
> > +      default:
> > +        hval += asso_values[static_cast<unsigned char>(str[7])];
> > +      /*FALLTHROUGH*/
> > +      case 7:
> > +        break;
> > +    }
> > +  return hval;
> > +}
> > +
> > +const struct cp_trait *
> > +cp_trait_lookup::find (const char *str, size_t len)
> > +{
> > +  enum
> > +    {
> > +      TOTAL_KEYWORDS = 45,
> > +      MIN_WORD_LENGTH = 7,
> > +      MAX_WORD_LENGTH = 37,
> > +      MIN_HASH_VALUE = 7,
> > +      MAX_HASH_VALUE = 85
> > +    };
> > +
> > +  static const struct cp_trait wordlist[] =
> > +    {
> > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > +      {"__bases", CPTK_BASES, 1, true},
> > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_pod", CPTK_IS_POD, 1, false},
> > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_union", CPTK_IS_UNION, 1, false},
> > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_class", CPTK_IS_CLASS, 1, false},
> > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_same", CPTK_IS_SAME, 2, false},
> > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_final", CPTK_IS_FINAL, 1, false},
> > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > +    };
> > +
> > +  static const signed char lookup[] =
> > +    {
> > +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> > +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > +      -1, 44
> > +    };
> > +
> > +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > +    {
> > +      unsigned int key = hash (str, len);
> > +
> > +      if (key <= MAX_HASH_VALUE)
> > +        {
> > +          int index = lookup[key];
> > +
> > +          if (index >= 0)
> > +            {
> > +              const char *s = wordlist[index].name;
> > +
> > +              if (*str == *s && !strcmp (str + 1, s + 1))
> > +                return &wordlist[index];
> > +            }
> > +        }
> > +    }
> > +  return 0;
> > +}
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 6e34952da99..62e134886fb 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> >    cik_simple_op = 4, /* Non-assignment operator name.  */
> >    cik_assign_op = 5, /* An assignment operator name.  */
> >    cik_conv_op = 6,   /* Conversion operator name.  */
> > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > +  cik_trait = 7,     /* Built-in trait name.  */
> >    cik_max
> >  };
> >
> > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> >      & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is for any operator name (including
> > -   conversions).  Value 4, 5, 6 or 7.  */
> > +   conversions).  Value 4, 5, or 6.  */
> >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> >
> >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> >     & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is the name of a type-conversion
> > -   operator.  Value 7.  */
> > +   operator.  Value 6.  */
> >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> >
> > +/* True if this identifier is the name of a built-in trait.  */
> > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > +
> >  /* True if this identifier is a new or delete operator.  */
> >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > index 64bcfb18196..f6e1f6a4075 100644
> > --- a/gcc/cp/lex.cc
> > +++ b/gcc/cp/lex.cc
> > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "langhooks.h"
> >
> >  static int interface_strcmp (const char *);
> > +static void init_cp_traits (void);
> >  static void init_cp_pragma (void);
> >
> >  static tree parse_strconst_pragma (const char *, int);
> > @@ -283,6 +284,23 @@ init_reswords (void)
> >      }
> >  }
> >
> > +/* Initialize the C++ traits.  */
> > +static void
> > +init_cp_traits (void)
> > +{
> > +  tree id;
> > +
> > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > +  id = get_identifier (NAME); \
> > +  set_identifier_kind (id, cik_trait);
> > +#include "cp/cp-trait.def"
> > +#undef DEFTRAIT
> > +
> > +  /* An alias for __is_same.  */
> > +  id = get_identifier ("__is_same_as");
> > +  set_identifier_kind (id, cik_trait);
> > +}
> > +
> >  static void
> >  init_cp_pragma (void)
> >  {
> > @@ -324,6 +342,7 @@ cxx_init (void)
> >    input_location = BUILTINS_LOCATION;
> >
> >    init_reswords ();
> > +  init_cp_traits ();
> >    init_tree ();
> >    init_cp_semantics ();
> >    init_operators ();
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index f3abae716fe..39952893ffa 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "contracts.h"
> >  #include "bitmap.h"
> >  #include "builtins.h"
> > +#include "cp-trait.h"
> >
> >
> >  /* The lexer.  */
> > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> >  static void cp_lexer_stop_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > +static const cp_trait *cp_lexer_lookup_trait
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_expr
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_type
> > +  (const cp_token *);
> >
> >  static cp_token_cache *cp_token_cache_new
> >    (cp_token *, cp_token *);
> > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      case RID_CONSTEVAL:
> >        return true;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      return true;
> > -
> >      default:
> >        if (keyword >= RID_FIRST_INT_N
> >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      }
> >  }
> >
> > +/* Look ups the corresponding built-in trait if a given token is
> > +   a built-in trait.  Otherwise, returns nullptr.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait (const cp_token *token)
> > +{
> > +  tree id = token->u.value;
> > +
> > +  if (token->type == CPP_NAME
> > +      && TREE_CODE (id) == IDENTIFIER_NODE
> > +      && IDENTIFIER_TRAIT_P (id))
> > +    {
> > +      const char *id_str = IDENTIFIER_POINTER (id);
> > +      const int id_len = IDENTIFIER_LENGTH (id);
> > +      return cp_trait_lookup::find (id_str, id_len);
> > +    }
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is an expression-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && !trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is a type-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_type (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> >  /* Return true if the next token is a keyword for a decl-specifier.  */
> >
> >  static bool
> > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> >    cp_token *token;
> >
> >    token = cp_lexer_peek_token (lexer);
> > +  if (cp_lexer_lookup_trait_type (token))
> > +    return true;
> >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> >  }
> >
> > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> >  static tree cp_parser_sizeof_operand
> >    (cp_parser *, enum rid);
> >  static cp_expr cp_parser_trait
> > -  (cp_parser *, enum rid);
> > +  (cp_parser *, const cp_trait *);
> >  static bool cp_parser_declares_only_class_p
> >    (cp_parser *);
> >  static void cp_parser_set_storage_class
> > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> >       case RID_OFFSETOF:
> >         return cp_parser_builtin_offsetof (parser);
> >
> > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > -     case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_EXPR
> > -       return cp_parser_trait (parser, token->keyword);
> > -
> >       // C++ concepts
> >       case RID_REQUIRES:
> >         return cp_parser_requires_expression (parser);
> > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> >        `::' as the beginning of a qualified-id, or the "operator"
> >        keyword.  */
> >      case CPP_NAME:
> > +      {
> > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > +     if (trait)
> > +       return cp_parser_trait (parser, trait);
> > +      }
> > +      /* FALLTHRU */
> >      case CPP_SCOPE:
> >      case CPP_TEMPLATE_ID:
> >      case CPP_NESTED_NAME_SPECIFIER:
> > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> >  /* Parse a builtin trait expression or type.  */
> >
> >  static cp_expr
> > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> >  {
> > -  cp_trait_kind kind;
> >    tree type1, type2 = NULL_TREE;
> > -  bool binary = false;
> > -  bool variadic = false;
> > -  bool type = false;
> > -
> > -  switch (keyword)
> > -    {
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:                  \
> > -      kind = CPTK_##CODE;             \
> > -      binary = (ARITY == 2);          \
> > -      variadic = (ARITY == -1);               \
> > -      type = (TCC == tcc_type);               \
> > -      break;
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > -    default:
> > -      gcc_unreachable ();
> > -    }
> > +  const bool binary = (trait->arity == 2);
> > +  const bool variadic = (trait->arity == -1);
> >
> >    /* Get location of initial token.  */
> >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    cp_lexer_consume_token (parser->lexer);
> >
> >    matching_parens parens;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> >    else
> >      parens.require_open (parser);
> >
> > -  if (kind == CPTK_IS_DEDUCIBLE)
> > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> >      {
> >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> >        type1 = cp_parser_id_expression (parser,
> > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >                                      /*optional_p=*/false);
> >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> >      }
> > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* __type_pack_element takes an expression as its first argument and uses
> >         template-id syntax instead of function call syntax (for consistency
> >         with Clang).  We special case these properties of __type_pack_element
> > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    if (type1 == error_mark_node)
> >      return error_mark_node;
> >
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      {
> >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >      }
> >
> >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* cp_parser_enclosed_template_argument_list above already took care
> >         of parsing the closing '>'.  */;
> >    else
> > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >
> >    /* Complete the trait expression, which may mean either processing
> >       the trait expr now or saving it for template instantiation.  */
> > -  switch (kind)
> > +  switch (trait->kind)
> >      {
> >      case CPTK_BASES:
> >        return cp_expr (finish_bases (type1, false), trait_loc);
> >      case CPTK_DIRECT_BASES:
> >        return cp_expr (finish_bases (type1, true), trait_loc);
> >      default:
> > -      if (type)
> > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > +      if (trait->type)
> > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> >        else
> > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> >      }
> >  }
> >
> > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> >
> >        return type;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      type = cp_parser_trait (parser, token->keyword);
> > +    default:
> > +      break;
> > +    }
> > +
> > +  /* If token is a type-yielding built-in traits, parse it.  */
> > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > +  if (trait)
> > +    {
> > +      type = cp_parser_trait (parser, trait);
> >        if (decl_specs)
> >       cp_parser_set_decl_spec_type (decl_specs, type,
> >                                     token,
> >                                     /*type_definition_p=*/false);
> >
> >        return type;
> > -
> > -    default:
> > -      break;
> >      }
> >
> >    /* If token is an already-parsed decltype not followed by ::,
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-15 21:04                   ` Ken Matsui
@ 2023-10-15 21:50                     ` Patrick Palka
  2023-10-15 21:52                       ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-15 21:50 UTC (permalink / raw)
  To: Ken Matsui; +Cc: Patrick Palka, Ken Matsui, gcc-patches, libstdc++, jason

[-- Attachment #1: Type: text/plain, Size: 40172 bytes --]

On Sun, 15 Oct 2023, Ken Matsui wrote:

> On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
> >
> > On Fri, 13 Oct 2023, Ken Matsui wrote:
> >
> > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > traits and uses gperf to look up the specific trait.  Rather than holding
> > > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > > cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > > identifier so that we accept the use of non-function-like built-in trait
> > > identifiers.
> >
> > Awesome!  It's great we won't have to rename any existing identifiers in
> > libstdc++ with this approach.
> >
> > I think this patch looks perfect, assuming we want to stick with the gperf
> > approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> > field which is currently only used for operator name identifiers to
> > optimize looking up operator information.  Could we reuse this field for
> > IDENTIFIER_TRAIT_P identifiers as well in order to store their
> > corresponding cp_trait_kind?  If so then I think we wouldn't need to use
> > gperf for the built-in traits at all, since the mapping from identifier
> > to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> > perhaps be a nice simplification (and just as fast if not faster than gperf)?
> >
> 
> Thank you! I think this way decreases the size of the compiler even if
> we do not see speed improvements. Since IDENTIFIER_CP_INDEX
> (base.u.bits.address_space) is an unsigned char (addr_space_t), we can
> have only up to 255 traits. Is this acceptable?

Good points.  Given there's so far around 150 standard library traits, a
limit of 255 should last us quite a while so IMHO it's acceptable :)

> 
> > >
> > > gcc/c-family/ChangeLog:
> > >
> > >       * c-common.cc (c_common_reswords): Remove all mappings of
> > >       built-in traits.
> > >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >       * Make-lang.in: Add targets to generate cp-trait.gperf and
> > >       cp-trait.h.
> > >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > >       cases for built-in traits.  Check for built-in traits via
> > >       the new cik_trait identifier.
> > >       * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> > >       (cik_trait): ... this.
> > >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> > >       built-in trait identifiers.
> > >       (cxx_init): Call init_cp_traits function.
> > >       * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > >       built-in trait from a token by gperf.
> > >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> > >       expression-yielding built-in trait.
> > >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > >       built-in trait.
> > >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > >       for built-in traits.
> > >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > >       type-yielding built-in traits.
> > >       (cp_parser_primary_expression): Remove all RID value cases for
> > >       built-in traits.  Handle expression-yielding built-in traits.
> > >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> > >       (cp_parser_simple_type_specifier): Remove all RID value cases
> > >       for built-in traits.  Handle type-yielding built-in traits.
> > >       * cp-trait-head.in: New file.
> > >       * cp-trait.gperf: New file.
> > >       * cp-trait.h: New file.
> > >
> > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > >  gcc/c-family/c-common.cc  |   7 --
> > >  gcc/c-family/c-common.h   |   5 -
> > >  gcc/cp/Make-lang.in       |  26 ++++
> > >  gcc/cp/cp-objcp-common.cc |   8 +-
> > >  gcc/cp/cp-trait-head.in   |  30 +++++
> > >  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
> > >  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
> > >  gcc/cp/cp-tree.h          |  14 ++-
> > >  gcc/cp/lex.cc             |  19 +++
> > >  gcc/cp/parser.cc          | 132 ++++++++++++--------
> > >  10 files changed, 492 insertions(+), 70 deletions(-)
> > >  create mode 100644 gcc/cp/cp-trait-head.in
> > >  create mode 100644 gcc/cp/cp-trait.gperf
> > >  create mode 100644 gcc/cp/cp-trait.h
> > >
> > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > index f044db5b797..21fd333ef57 100644
> > > --- a/gcc/c-family/c-common.cc
> > > +++ b/gcc/c-family/c-common.cc
> > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> > >    { "while",         RID_WHILE,      0 },
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -  /* An alias for __is_same.  */
> > > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > > -
> > >    /* C++ transactional memory.  */
> > >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > index 1fdba7ef3ea..051a442e0f4 100644
> > > --- a/gcc/c-family/c-common.h
> > > +++ b/gcc/c-family/c-common.h
> > > @@ -168,11 +168,6 @@ enum rid
> > >    RID_BUILTIN_LAUNDER,
> > >    RID_BUILTIN_BIT_CAST,
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -  RID_##CODE,
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -
> > >    /* C++11 */
> > >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > >
> > > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > > index 2727fb7f8cc..a67d1c3e9f3 100644
> > > --- a/gcc/cp/Make-lang.in
> > > +++ b/gcc/cp/Make-lang.in
> > > @@ -34,6 +34,8 @@
> > >  # - the compiler proper (eg: cc1plus)
> > >  # - define the names for selecting the language in LANGUAGES.
> > >
> > > +AWK = @AWK@
> > > +
> > >  # Actual names to use when installing a native compiler.
> > >  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> > >  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > > @@ -186,6 +188,30 @@ endif
> > >  # This is the file that depends on the generated header file.
> > >  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> > >
> > > +# We always need the dependency on the .gperf file
> > > +# because it itself is generated.
> > > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > > +else
> > > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > > +endif
> > > +     gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > > +             $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > > +
> > > +# The cp-trait.gperf file itself is generated from
> > > +# cp-trait-head.in and cp-trait.def files.
> > > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > > +     cat $< > $@
> > > +     $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > > +             type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > > +             gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > > +             gsub(/\)/, "", $$3); \
> > > +             print $$2", CPTK_" $$1", "$$3", "type; \
> > > +     }' $(srcdir)/cp/cp-trait.def >> $@
> > > +
> > > +# This is the file that depends on the generated header file.
> > > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > > +
> > >  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> > >  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> > >
> > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > index 93b027b80ce..b1adacfec07 100644
> > > --- a/gcc/cp/cp-objcp-common.cc
> > > +++ b/gcc/cp/cp-objcp-common.cc
> > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > >       }
> > >      }
> > >
> > > +  /* Check for built-in traits.  */
> > > +  if (IDENTIFIER_TRAIT_P (id))
> > > +    return true;
> > > +
> > >    /* Also detect common reserved C++ words that aren't strictly built-in
> > >       functions.  */
> > >    switch (C_RID_CODE (id))
> > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > >      case RID_BUILTIN_ASSOC_BARRIER:
> > >      case RID_BUILTIN_BIT_CAST:
> > >      case RID_OFFSETOF:
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > >        return true;
> > >      default:
> > >        break;
> > > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > > new file mode 100644
> > > index 00000000000..9357eea1238
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait-head.in
> > > @@ -0,0 +1,30 @@
> > > +%language=C++
> > > +%define class-name cp_trait_lookup
> > > +%struct-type
> > > +%{
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3.  If not see
> > > +<http://www.gnu.org/licenses/>.  */
> > > +%}
> > > +struct cp_trait {
> > > +  const char *name;
> > > +  enum cp_trait_kind kind;
> > > +  short arity;
> > > +  bool type;
> > > +};
> > > +%%
> > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > > new file mode 100644
> > > index 00000000000..47e3c1af499
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait.gperf
> > > @@ -0,0 +1,74 @@
> > > +%language=C++
> > > +%define class-name cp_trait_lookup
> > > +%struct-type
> > > +%{
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3.  If not see
> > > +<http://www.gnu.org/licenses/>.  */
> > > +%}
> > > +struct cp_trait {
> > > +  const char *name;
> > > +  enum cp_trait_kind kind;
> > > +  short arity;
> > > +  bool type;
> > > +};
> > > +%%
> > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > > +"__is_class", CPTK_IS_CLASS, 1, false
> > > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > > +"__is_enum", CPTK_IS_ENUM, 1, false
> > > +"__is_final", CPTK_IS_FINAL, 1, false
> > > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > > +"__is_pod", CPTK_IS_POD, 1, false
> > > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > > +"__is_same", CPTK_IS_SAME, 2, false
> > > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > > +"__is_union", CPTK_IS_UNION, 1, false
> > > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > > +"__bases", CPTK_BASES, 1, true
> > > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > > new file mode 100644
> > > index 00000000000..97ba8492d15
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait.h
> > > @@ -0,0 +1,247 @@
> > > +/* C++ code produced by gperf version 3.1 */
> > > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> > > +
> > > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > > +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > > +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > > +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > > +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > > +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > > +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > > +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > > +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > > +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > > +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > > +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > > +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > > +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > > +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > > +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > > +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > > +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > > +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > > +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > > +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > > +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > > +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > > +/* The character set is not based on ISO-646.  */
> > > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > > +#endif
> > > +
> > > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > > +
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3.  If not see
> > > +<http://www.gnu.org/licenses/>.  */
> > > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > > +struct cp_trait {
> > > +  const char *name;
> > > +  enum cp_trait_kind kind;
> > > +  short arity;
> > > +  bool type;
> > > +};
> > > +/* maximum key range = 79, duplicates = 0 */
> > > +
> > > +class cp_trait_lookup
> > > +{
> > > +private:
> > > +  static inline unsigned int hash (const char *str, size_t len);
> > > +public:
> > > +  static const struct cp_trait *find (const char *str, size_t len);
> > > +};
> > > +
> > > +inline unsigned int
> > > +cp_trait_lookup::hash (const char *str, size_t len)
> > > +{
> > > +  static const unsigned char asso_values[] =
> > > +    {
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> > > +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> > > +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> > > +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > +      86, 86, 86, 86, 86, 86
> > > +    };
> > > +  unsigned int hval = len;
> > > +
> > > +  switch (hval)
> > > +    {
> > > +      default:
> > > +        hval += asso_values[static_cast<unsigned char>(str[7])];
> > > +      /*FALLTHROUGH*/
> > > +      case 7:
> > > +        break;
> > > +    }
> > > +  return hval;
> > > +}
> > > +
> > > +const struct cp_trait *
> > > +cp_trait_lookup::find (const char *str, size_t len)
> > > +{
> > > +  enum
> > > +    {
> > > +      TOTAL_KEYWORDS = 45,
> > > +      MIN_WORD_LENGTH = 7,
> > > +      MAX_WORD_LENGTH = 37,
> > > +      MIN_HASH_VALUE = 7,
> > > +      MAX_HASH_VALUE = 85
> > > +    };
> > > +
> > > +  static const struct cp_trait wordlist[] =
> > > +    {
> > > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__bases", CPTK_BASES, 1, true},
> > > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_pod", CPTK_IS_POD, 1, false},
> > > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> > > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_union", CPTK_IS_UNION, 1, false},
> > > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_class", CPTK_IS_CLASS, 1, false},
> > > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_same", CPTK_IS_SAME, 2, false},
> > > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> > > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_final", CPTK_IS_FINAL, 1, false},
> > > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > > +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > > +    };
> > > +
> > > +  static const signed char lookup[] =
> > > +    {
> > > +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> > > +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > > +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > > +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > > +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > > +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > > +      -1, 44
> > > +    };
> > > +
> > > +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > > +    {
> > > +      unsigned int key = hash (str, len);
> > > +
> > > +      if (key <= MAX_HASH_VALUE)
> > > +        {
> > > +          int index = lookup[key];
> > > +
> > > +          if (index >= 0)
> > > +            {
> > > +              const char *s = wordlist[index].name;
> > > +
> > > +              if (*str == *s && !strcmp (str + 1, s + 1))
> > > +                return &wordlist[index];
> > > +            }
> > > +        }
> > > +    }
> > > +  return 0;
> > > +}
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index 6e34952da99..62e134886fb 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > >    cik_simple_op = 4, /* Non-assignment operator name.  */
> > >    cik_assign_op = 5, /* An assignment operator name.  */
> > >    cik_conv_op = 6,   /* Conversion operator name.  */
> > > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > > +  cik_trait = 7,     /* Built-in trait name.  */
> > >    cik_max
> > >  };
> > >
> > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > >      & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > >  /* True if this identifier is for any operator name (including
> > > -   conversions).  Value 4, 5, 6 or 7.  */
> > > +   conversions).  Value 4, 5, or 6.  */
> > >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > >
> > >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> > >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > >     & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > >  /* True if this identifier is the name of a type-conversion
> > > -   operator.  Value 7.  */
> > > +   operator.  Value 6.  */
> > >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> > >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> > >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> > >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > >
> > > +/* True if this identifier is the name of a built-in trait.  */
> > > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > > +
> > >  /* True if this identifier is a new or delete operator.  */
> > >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> > >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > index 64bcfb18196..f6e1f6a4075 100644
> > > --- a/gcc/cp/lex.cc
> > > +++ b/gcc/cp/lex.cc
> > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> > >  #include "langhooks.h"
> > >
> > >  static int interface_strcmp (const char *);
> > > +static void init_cp_traits (void);
> > >  static void init_cp_pragma (void);
> > >
> > >  static tree parse_strconst_pragma (const char *, int);
> > > @@ -283,6 +284,23 @@ init_reswords (void)
> > >      }
> > >  }
> > >
> > > +/* Initialize the C++ traits.  */
> > > +static void
> > > +init_cp_traits (void)
> > > +{
> > > +  tree id;
> > > +
> > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > +  id = get_identifier (NAME); \
> > > +  set_identifier_kind (id, cik_trait);
> > > +#include "cp/cp-trait.def"
> > > +#undef DEFTRAIT
> > > +
> > > +  /* An alias for __is_same.  */
> > > +  id = get_identifier ("__is_same_as");
> > > +  set_identifier_kind (id, cik_trait);
> > > +}
> > > +
> > >  static void
> > >  init_cp_pragma (void)
> > >  {
> > > @@ -324,6 +342,7 @@ cxx_init (void)
> > >    input_location = BUILTINS_LOCATION;
> > >
> > >    init_reswords ();
> > > +  init_cp_traits ();
> > >    init_tree ();
> > >    init_cp_semantics ();
> > >    init_operators ();
> > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > index f3abae716fe..39952893ffa 100644
> > > --- a/gcc/cp/parser.cc
> > > +++ b/gcc/cp/parser.cc
> > > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
> > >  #include "contracts.h"
> > >  #include "bitmap.h"
> > >  #include "builtins.h"
> > > +#include "cp-trait.h"
> > >
> > >
> > >  /* The lexer.  */
> > > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > >  static void cp_lexer_stop_debugging
> > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > +static const cp_trait *cp_lexer_lookup_trait
> > > +  (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > +  (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > +  (const cp_token *);
> > >
> > >  static cp_token_cache *cp_token_cache_new
> > >    (cp_token *, cp_token *);
> > > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > >      case RID_CONSTEVAL:
> > >        return true;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > -      return true;
> > > -
> > >      default:
> > >        if (keyword >= RID_FIRST_INT_N
> > >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > >      }
> > >  }
> > >
> > > +/* Look ups the corresponding built-in trait if a given token is
> > > +   a built-in trait.  Otherwise, returns nullptr.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait (const cp_token *token)
> > > +{
> > > +  tree id = token->u.value;
> > > +
> > > +  if (token->type == CPP_NAME
> > > +      && TREE_CODE (id) == IDENTIFIER_NODE
> > > +      && IDENTIFIER_TRAIT_P (id))
> > > +    {
> > > +      const char *id_str = IDENTIFIER_POINTER (id);
> > > +      const int id_len = IDENTIFIER_LENGTH (id);
> > > +      return cp_trait_lookup::find (id_str, id_len);
> > > +    }
> > > +  return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is an expression-yielding
> > > +   built-in trait.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > +{
> > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > +  if (trait && !trait->type)
> > > +    return trait;
> > > +
> > > +  return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is a type-yielding
> > > +   built-in trait.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > +{
> > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > +  if (trait && trait->type)
> > > +    return trait;
> > > +
> > > +  return nullptr;
> > > +}
> > > +
> > >  /* Return true if the next token is a keyword for a decl-specifier.  */
> > >
> > >  static bool
> > > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > >    cp_token *token;
> > >
> > >    token = cp_lexer_peek_token (lexer);
> > > +  if (cp_lexer_lookup_trait_type (token))
> > > +    return true;
> > >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> > >  }
> > >
> > > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> > >  static tree cp_parser_sizeof_operand
> > >    (cp_parser *, enum rid);
> > >  static cp_expr cp_parser_trait
> > > -  (cp_parser *, enum rid);
> > > +  (cp_parser *, const cp_trait *);
> > >  static bool cp_parser_declares_only_class_p
> > >    (cp_parser *);
> > >  static void cp_parser_set_storage_class
> > > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > >       case RID_OFFSETOF:
> > >         return cp_parser_builtin_offsetof (parser);
> > >
> > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > -     case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_EXPR
> > > -       return cp_parser_trait (parser, token->keyword);
> > > -
> > >       // C++ concepts
> > >       case RID_REQUIRES:
> > >         return cp_parser_requires_expression (parser);
> > > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > >        `::' as the beginning of a qualified-id, or the "operator"
> > >        keyword.  */
> > >      case CPP_NAME:
> > > +      {
> > > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > +     if (trait)
> > > +       return cp_parser_trait (parser, trait);
> > > +      }
> > > +      /* FALLTHRU */
> > >      case CPP_SCOPE:
> > >      case CPP_TEMPLATE_ID:
> > >      case CPP_NESTED_NAME_SPECIFIER:
> > > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > >  /* Parse a builtin trait expression or type.  */
> > >
> > >  static cp_expr
> > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > >  {
> > > -  cp_trait_kind kind;
> > >    tree type1, type2 = NULL_TREE;
> > > -  bool binary = false;
> > > -  bool variadic = false;
> > > -  bool type = false;
> > > -
> > > -  switch (keyword)
> > > -    {
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -    case RID_##CODE:                  \
> > > -      kind = CPTK_##CODE;             \
> > > -      binary = (ARITY == 2);          \
> > > -      variadic = (ARITY == -1);               \
> > > -      type = (TCC == tcc_type);               \
> > > -      break;
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > > -    default:
> > > -      gcc_unreachable ();
> > > -    }
> > > +  const bool binary = (trait->arity == 2);
> > > +  const bool variadic = (trait->arity == -1);
> > >
> > >    /* Get location of initial token.  */
> > >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >    cp_lexer_consume_token (parser->lexer);
> > >
> > >    matching_parens parens;
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> > >    else
> > >      parens.require_open (parser);
> > >
> > > -  if (kind == CPTK_IS_DEDUCIBLE)
> > > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> > >      {
> > >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > >        type1 = cp_parser_id_expression (parser,
> > > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >                                      /*optional_p=*/false);
> > >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > >      }
> > > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      /* __type_pack_element takes an expression as its first argument and uses
> > >         template-id syntax instead of function call syntax (for consistency
> > >         with Clang).  We special case these properties of __type_pack_element
> > > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >    if (type1 == error_mark_node)
> > >      return error_mark_node;
> > >
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      {
> > >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >      }
> > >
> > >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      /* cp_parser_enclosed_template_argument_list above already took care
> > >         of parsing the closing '>'.  */;
> > >    else
> > > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >
> > >    /* Complete the trait expression, which may mean either processing
> > >       the trait expr now or saving it for template instantiation.  */
> > > -  switch (kind)
> > > +  switch (trait->kind)
> > >      {
> > >      case CPTK_BASES:
> > >        return cp_expr (finish_bases (type1, false), trait_loc);
> > >      case CPTK_DIRECT_BASES:
> > >        return cp_expr (finish_bases (type1, true), trait_loc);
> > >      default:
> > > -      if (type)
> > > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > +      if (trait->type)
> > > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > >        else
> > > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > >      }
> > >  }
> > >
> > > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > >
> > >        return type;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > -      type = cp_parser_trait (parser, token->keyword);
> > > +    default:
> > > +      break;
> > > +    }
> > > +
> > > +  /* If token is a type-yielding built-in traits, parse it.  */
> > > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > +  if (trait)
> > > +    {
> > > +      type = cp_parser_trait (parser, trait);
> > >        if (decl_specs)
> > >       cp_parser_set_decl_spec_type (decl_specs, type,
> > >                                     token,
> > >                                     /*type_definition_p=*/false);
> > >
> > >        return type;
> > > -
> > > -    default:
> > > -      break;
> > >      }
> > >
> > >    /* If token is an already-parsed decltype not followed by ::,
> > > --
> > > 2.42.0
> > >
> > >
> >
> 
> 

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf
  2023-10-15 21:50                     ` Patrick Palka
@ 2023-10-15 21:52                       ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-15 21:52 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++, jason

On Sun, Oct 15, 2023 at 2:50 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
> > >
> > > On Fri, 13 Oct 2023, Ken Matsui wrote:
> > >
> > > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > > traits and uses gperf to look up the specific trait.  Rather than holding
> > > > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > > > cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > > > identifier so that we accept the use of non-function-like built-in trait
> > > > identifiers.
> > >
> > > Awesome!  It's great we won't have to rename any existing identifiers in
> > > libstdc++ with this approach.
> > >
> > > I think this patch looks perfect, assuming we want to stick with the gperf
> > > approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> > > field which is currently only used for operator name identifiers to
> > > optimize looking up operator information.  Could we reuse this field for
> > > IDENTIFIER_TRAIT_P identifiers as well in order to store their
> > > corresponding cp_trait_kind?  If so then I think we wouldn't need to use
> > > gperf for the built-in traits at all, since the mapping from identifier
> > > to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> > > perhaps be a nice simplification (and just as fast if not faster than gperf)?
> > >
> >
> > Thank you! I think this way decreases the size of the compiler even if
> > we do not see speed improvements. Since IDENTIFIER_CP_INDEX
> > (base.u.bits.address_space) is an unsigned char (addr_space_t), we can
> > have only up to 255 traits. Is this acceptable?
>
> Good points.  Given there's so far around 150 standard library traits, a
> limit of 255 should last us quite a while so IMHO it's acceptable :)
>

Sounds great! I will update the patch in this way. Thank you!

> >
> > > >
> > > > gcc/c-family/ChangeLog:
> > > >
> > > >       * c-common.cc (c_common_reswords): Remove all mappings of
> > > >       built-in traits.
> > > >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >       * Make-lang.in: Add targets to generate cp-trait.gperf and
> > > >       cp-trait.h.
> > > >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > > >       cases for built-in traits.  Check for built-in traits via
> > > >       the new cik_trait identifier.
> > > >       * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> > > >       (cik_trait): ... this.
> > > >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > > >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > > >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> > > >       built-in trait identifiers.
> > > >       (cxx_init): Call init_cp_traits function.
> > > >       * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > > >       built-in trait from a token by gperf.
> > > >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> > > >       expression-yielding built-in trait.
> > > >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > > >       built-in trait.
> > > >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > > >       for built-in traits.
> > > >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > > >       type-yielding built-in traits.
> > > >       (cp_parser_primary_expression): Remove all RID value cases for
> > > >       built-in traits.  Handle expression-yielding built-in traits.
> > > >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> > > >       (cp_parser_simple_type_specifier): Remove all RID value cases
> > > >       for built-in traits.  Handle type-yielding built-in traits.
> > > >       * cp-trait-head.in: New file.
> > > >       * cp-trait.gperf: New file.
> > > >       * cp-trait.h: New file.
> > > >
> > > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > > ---
> > > >  gcc/c-family/c-common.cc  |   7 --
> > > >  gcc/c-family/c-common.h   |   5 -
> > > >  gcc/cp/Make-lang.in       |  26 ++++
> > > >  gcc/cp/cp-objcp-common.cc |   8 +-
> > > >  gcc/cp/cp-trait-head.in   |  30 +++++
> > > >  gcc/cp/cp-trait.gperf     |  74 ++++++++++++
> > > >  gcc/cp/cp-trait.h         | 247 ++++++++++++++++++++++++++++++++++++++
> > > >  gcc/cp/cp-tree.h          |  14 ++-
> > > >  gcc/cp/lex.cc             |  19 +++
> > > >  gcc/cp/parser.cc          | 132 ++++++++++++--------
> > > >  10 files changed, 492 insertions(+), 70 deletions(-)
> > > >  create mode 100644 gcc/cp/cp-trait-head.in
> > > >  create mode 100644 gcc/cp/cp-trait.gperf
> > > >  create mode 100644 gcc/cp/cp-trait.h
> > > >
> > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > > index f044db5b797..21fd333ef57 100644
> > > > --- a/gcc/c-family/c-common.cc
> > > > +++ b/gcc/c-family/c-common.cc
> > > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > > >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> > > >    { "while",         RID_WHILE,      0 },
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -  /* An alias for __is_same.  */
> > > > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > > > -
> > > >    /* C++ transactional memory.  */
> > > >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > > >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > > index 1fdba7ef3ea..051a442e0f4 100644
> > > > --- a/gcc/c-family/c-common.h
> > > > +++ b/gcc/c-family/c-common.h
> > > > @@ -168,11 +168,6 @@ enum rid
> > > >    RID_BUILTIN_LAUNDER,
> > > >    RID_BUILTIN_BIT_CAST,
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -  RID_##CODE,
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -
> > > >    /* C++11 */
> > > >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > > >
> > > > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > > > index 2727fb7f8cc..a67d1c3e9f3 100644
> > > > --- a/gcc/cp/Make-lang.in
> > > > +++ b/gcc/cp/Make-lang.in
> > > > @@ -34,6 +34,8 @@
> > > >  # - the compiler proper (eg: cc1plus)
> > > >  # - define the names for selecting the language in LANGUAGES.
> > > >
> > > > +AWK = @AWK@
> > > > +
> > > >  # Actual names to use when installing a native compiler.
> > > >  CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> > > >  GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > > > @@ -186,6 +188,30 @@ endif
> > > >  # This is the file that depends on the generated header file.
> > > >  cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> > > >
> > > > +# We always need the dependency on the .gperf file
> > > > +# because it itself is generated.
> > > > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > > > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > > > +else
> > > > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > > > +endif
> > > > +     gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > > > +             $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > > > +
> > > > +# The cp-trait.gperf file itself is generated from
> > > > +# cp-trait-head.in and cp-trait.def files.
> > > > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > > > +     cat $< > $@
> > > > +     $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > > > +             type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > > > +             gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > > > +             gsub(/\)/, "", $$3); \
> > > > +             print $$2", CPTK_" $$1", "$$3", "type; \
> > > > +     }' $(srcdir)/cp/cp-trait.def >> $@
> > > > +
> > > > +# This is the file that depends on the generated header file.
> > > > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > > > +
> > > >  components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> > > >  components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> > > >
> > > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > > index 93b027b80ce..b1adacfec07 100644
> > > > --- a/gcc/cp/cp-objcp-common.cc
> > > > +++ b/gcc/cp/cp-objcp-common.cc
> > > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > > >       }
> > > >      }
> > > >
> > > > +  /* Check for built-in traits.  */
> > > > +  if (IDENTIFIER_TRAIT_P (id))
> > > > +    return true;
> > > > +
> > > >    /* Also detect common reserved C++ words that aren't strictly built-in
> > > >       functions.  */
> > > >    switch (C_RID_CODE (id))
> > > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > > >      case RID_BUILTIN_ASSOC_BARRIER:
> > > >      case RID_BUILTIN_BIT_CAST:
> > > >      case RID_OFFSETOF:
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > >        return true;
> > > >      default:
> > > >        break;
> > > > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > > > new file mode 100644
> > > > index 00000000000..9357eea1238
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait-head.in
> > > > @@ -0,0 +1,30 @@
> > > > +%language=C++
> > > > +%define class-name cp_trait_lookup
> > > > +%struct-type
> > > > +%{
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3.  If not see
> > > > +<http://www.gnu.org/licenses/>.  */
> > > > +%}
> > > > +struct cp_trait {
> > > > +  const char *name;
> > > > +  enum cp_trait_kind kind;
> > > > +  short arity;
> > > > +  bool type;
> > > > +};
> > > > +%%
> > > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > > > new file mode 100644
> > > > index 00000000000..47e3c1af499
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait.gperf
> > > > @@ -0,0 +1,74 @@
> > > > +%language=C++
> > > > +%define class-name cp_trait_lookup
> > > > +%struct-type
> > > > +%{
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3.  If not see
> > > > +<http://www.gnu.org/licenses/>.  */
> > > > +%}
> > > > +struct cp_trait {
> > > > +  const char *name;
> > > > +  enum cp_trait_kind kind;
> > > > +  short arity;
> > > > +  bool type;
> > > > +};
> > > > +%%
> > > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > > > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > > > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > > > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > > > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > > > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > > > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > > > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > > > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > > > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > > > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > > > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > > > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > > > +"__is_class", CPTK_IS_CLASS, 1, false
> > > > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > > > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > > > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > > > +"__is_enum", CPTK_IS_ENUM, 1, false
> > > > +"__is_final", CPTK_IS_FINAL, 1, false
> > > > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > > > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > > > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > > > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > > > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > > > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > > > +"__is_pod", CPTK_IS_POD, 1, false
> > > > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > > > +"__is_same", CPTK_IS_SAME, 2, false
> > > > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > > > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > > > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > > > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > > > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > > > +"__is_union", CPTK_IS_UNION, 1, false
> > > > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > > > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > > > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > > > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > > > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > > > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > > > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > > > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > > > +"__bases", CPTK_BASES, 1, true
> > > > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > > > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > > > new file mode 100644
> > > > index 00000000000..97ba8492d15
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait.h
> > > > @@ -0,0 +1,247 @@
> > > > +/* C++ code produced by gperf version 3.1 */
> > > > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf  */
> > > > +
> > > > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > > > +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > > > +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > > > +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > > > +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > > > +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > > > +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > > > +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > > > +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > > > +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > > > +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > > > +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > > > +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > > > +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > > > +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > > > +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > > > +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > > > +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > > > +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > > > +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > > > +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > > > +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > > > +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > > > +/* The character set is not based on ISO-646.  */
> > > > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > > > +#endif
> > > > +
> > > > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > > > +
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3.  If not see
> > > > +<http://www.gnu.org/licenses/>.  */
> > > > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > > > +struct cp_trait {
> > > > +  const char *name;
> > > > +  enum cp_trait_kind kind;
> > > > +  short arity;
> > > > +  bool type;
> > > > +};
> > > > +/* maximum key range = 79, duplicates = 0 */
> > > > +
> > > > +class cp_trait_lookup
> > > > +{
> > > > +private:
> > > > +  static inline unsigned int hash (const char *str, size_t len);
> > > > +public:
> > > > +  static const struct cp_trait *find (const char *str, size_t len);
> > > > +};
> > > > +
> > > > +inline unsigned int
> > > > +cp_trait_lookup::hash (const char *str, size_t len)
> > > > +{
> > > > +  static const unsigned char asso_values[] =
> > > > +    {
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86,  1, 86, 86,
> > > > +       0, 35, 86,  0, 86,  0, 86, 86, 10, 10,
> > > > +      50, 15, 55, 86, 30,  5, 15,  0, 86, 86,
> > > > +      86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > +      86, 86, 86, 86, 86, 86
> > > > +    };
> > > > +  unsigned int hval = len;
> > > > +
> > > > +  switch (hval)
> > > > +    {
> > > > +      default:
> > > > +        hval += asso_values[static_cast<unsigned char>(str[7])];
> > > > +      /*FALLTHROUGH*/
> > > > +      case 7:
> > > > +        break;
> > > > +    }
> > > > +  return hval;
> > > > +}
> > > > +
> > > > +const struct cp_trait *
> > > > +cp_trait_lookup::find (const char *str, size_t len)
> > > > +{
> > > > +  enum
> > > > +    {
> > > > +      TOTAL_KEYWORDS = 45,
> > > > +      MIN_WORD_LENGTH = 7,
> > > > +      MAX_WORD_LENGTH = 37,
> > > > +      MIN_HASH_VALUE = 7,
> > > > +      MAX_HASH_VALUE = 85
> > > > +    };
> > > > +
> > > > +  static const struct cp_trait wordlist[] =
> > > > +    {
> > > > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__bases", CPTK_BASES, 1, true},
> > > > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_pod", CPTK_IS_POD, 1, false},
> > > > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_enum", CPTK_IS_ENUM, 1, false},
> > > > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_union", CPTK_IS_UNION, 1, false},
> > > > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_class", CPTK_IS_CLASS, 1, false},
> > > > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > > > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > > > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > > > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > > > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > > > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_same", CPTK_IS_SAME, 2, false},
> > > > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > > > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > > > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_same_as", CPTK_IS_SAME, 2, false},
> > > > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > > > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > > > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > > > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > > > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > > > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > > > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > > > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > > > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > > > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > > > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > > > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > > > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > > > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > > > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > > > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > > > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > > > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > > > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > > > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > > > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > > > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > > > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > > > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_final", CPTK_IS_FINAL, 1, false},
> > > > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > > > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > > > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > > > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > > > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > > > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > > > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > > > +      {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > > > +    };
> > > > +
> > > > +  static const signed char lookup[] =
> > > > +    {
> > > > +      -1, -1, -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5, -1,
> > > > +       6,  7, -1,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > > > +      19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > > > +      29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > > > +      -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > > > +      41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > > > +      -1, 44
> > > > +    };
> > > > +
> > > > +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > > > +    {
> > > > +      unsigned int key = hash (str, len);
> > > > +
> > > > +      if (key <= MAX_HASH_VALUE)
> > > > +        {
> > > > +          int index = lookup[key];
> > > > +
> > > > +          if (index >= 0)
> > > > +            {
> > > > +              const char *s = wordlist[index].name;
> > > > +
> > > > +              if (*str == *s && !strcmp (str + 1, s + 1))
> > > > +                return &wordlist[index];
> > > > +            }
> > > > +        }
> > > > +    }
> > > > +  return 0;
> > > > +}
> > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > > index 6e34952da99..62e134886fb 100644
> > > > --- a/gcc/cp/cp-tree.h
> > > > +++ b/gcc/cp/cp-tree.h
> > > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > > >    cik_simple_op = 4, /* Non-assignment operator name.  */
> > > >    cik_assign_op = 5, /* An assignment operator name.  */
> > > >    cik_conv_op = 6,   /* Conversion operator name.  */
> > > > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > > > +  cik_trait = 7,     /* Built-in trait name.  */
> > > >    cik_max
> > > >  };
> > > >
> > > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > > >      & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > >  /* True if this identifier is for any operator name (including
> > > > -   conversions).  Value 4, 5, 6 or 7.  */
> > > > +   conversions).  Value 4, 5, or 6.  */
> > > >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > > > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > > > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > > >
> > > >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> > > >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > > >     & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > >  /* True if this identifier is the name of a type-conversion
> > > > -   operator.  Value 7.  */
> > > > +   operator.  Value 6.  */
> > > >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> > > >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> > > >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> > > >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > > >
> > > > +/* True if this identifier is the name of a built-in trait.  */
> > > > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > > > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > > > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > > > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > > > +
> > > >  /* True if this identifier is a new or delete operator.  */
> > > >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> > > >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > > index 64bcfb18196..f6e1f6a4075 100644
> > > > --- a/gcc/cp/lex.cc
> > > > +++ b/gcc/cp/lex.cc
> > > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> > > >  #include "langhooks.h"
> > > >
> > > >  static int interface_strcmp (const char *);
> > > > +static void init_cp_traits (void);
> > > >  static void init_cp_pragma (void);
> > > >
> > > >  static tree parse_strconst_pragma (const char *, int);
> > > > @@ -283,6 +284,23 @@ init_reswords (void)
> > > >      }
> > > >  }
> > > >
> > > > +/* Initialize the C++ traits.  */
> > > > +static void
> > > > +init_cp_traits (void)
> > > > +{
> > > > +  tree id;
> > > > +
> > > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > +  id = get_identifier (NAME); \
> > > > +  set_identifier_kind (id, cik_trait);
> > > > +#include "cp/cp-trait.def"
> > > > +#undef DEFTRAIT
> > > > +
> > > > +  /* An alias for __is_same.  */
> > > > +  id = get_identifier ("__is_same_as");
> > > > +  set_identifier_kind (id, cik_trait);
> > > > +}
> > > > +
> > > >  static void
> > > >  init_cp_pragma (void)
> > > >  {
> > > > @@ -324,6 +342,7 @@ cxx_init (void)
> > > >    input_location = BUILTINS_LOCATION;
> > > >
> > > >    init_reswords ();
> > > > +  init_cp_traits ();
> > > >    init_tree ();
> > > >    init_cp_semantics ();
> > > >    init_operators ();
> > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > > index f3abae716fe..39952893ffa 100644
> > > > --- a/gcc/cp/parser.cc
> > > > +++ b/gcc/cp/parser.cc
> > > > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
> > > >  #include "contracts.h"
> > > >  #include "bitmap.h"
> > > >  #include "builtins.h"
> > > > +#include "cp-trait.h"
> > > >
> > > >
> > > >  /* The lexer.  */
> > > > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> > > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > >  static void cp_lexer_stop_debugging
> > > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > > +static const cp_trait *cp_lexer_lookup_trait
> > > > +  (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > > +  (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > > +  (const cp_token *);
> > > >
> > > >  static cp_token_cache *cp_token_cache_new
> > > >    (cp_token *, cp_token *);
> > > > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > >      case RID_CONSTEVAL:
> > > >        return true;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > -      return true;
> > > > -
> > > >      default:
> > > >        if (keyword >= RID_FIRST_INT_N
> > > >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > >      }
> > > >  }
> > > >
> > > > +/* Look ups the corresponding built-in trait if a given token is
> > > > +   a built-in trait.  Otherwise, returns nullptr.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait (const cp_token *token)
> > > > +{
> > > > +  tree id = token->u.value;
> > > > +
> > > > +  if (token->type == CPP_NAME
> > > > +      && TREE_CODE (id) == IDENTIFIER_NODE
> > > > +      && IDENTIFIER_TRAIT_P (id))
> > > > +    {
> > > > +      const char *id_str = IDENTIFIER_POINTER (id);
> > > > +      const int id_len = IDENTIFIER_LENGTH (id);
> > > > +      return cp_trait_lookup::find (id_str, id_len);
> > > > +    }
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is an expression-yielding
> > > > +   built-in trait.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > > +{
> > > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > +  if (trait && !trait->type)
> > > > +    return trait;
> > > > +
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is a type-yielding
> > > > +   built-in trait.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > > +{
> > > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > +  if (trait && trait->type)
> > > > +    return trait;
> > > > +
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > >  /* Return true if the next token is a keyword for a decl-specifier.  */
> > > >
> > > >  static bool
> > > > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > > >    cp_token *token;
> > > >
> > > >    token = cp_lexer_peek_token (lexer);
> > > > +  if (cp_lexer_lookup_trait_type (token))
> > > > +    return true;
> > > >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> > > >  }
> > > >
> > > > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> > > >  static tree cp_parser_sizeof_operand
> > > >    (cp_parser *, enum rid);
> > > >  static cp_expr cp_parser_trait
> > > > -  (cp_parser *, enum rid);
> > > > +  (cp_parser *, const cp_trait *);
> > > >  static bool cp_parser_declares_only_class_p
> > > >    (cp_parser *);
> > > >  static void cp_parser_set_storage_class
> > > > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > > >       case RID_OFFSETOF:
> > > >         return cp_parser_builtin_offsetof (parser);
> > > >
> > > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > > -     case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_EXPR
> > > > -       return cp_parser_trait (parser, token->keyword);
> > > > -
> > > >       // C++ concepts
> > > >       case RID_REQUIRES:
> > > >         return cp_parser_requires_expression (parser);
> > > > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > > >        `::' as the beginning of a qualified-id, or the "operator"
> > > >        keyword.  */
> > > >      case CPP_NAME:
> > > > +      {
> > > > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > > +     if (trait)
> > > > +       return cp_parser_trait (parser, trait);
> > > > +      }
> > > > +      /* FALLTHRU */
> > > >      case CPP_SCOPE:
> > > >      case CPP_TEMPLATE_ID:
> > > >      case CPP_NESTED_NAME_SPECIFIER:
> > > > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > > >  /* Parse a builtin trait expression or type.  */
> > > >
> > > >  static cp_expr
> > > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > > >  {
> > > > -  cp_trait_kind kind;
> > > >    tree type1, type2 = NULL_TREE;
> > > > -  bool binary = false;
> > > > -  bool variadic = false;
> > > > -  bool type = false;
> > > > -
> > > > -  switch (keyword)
> > > > -    {
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:                  \
> > > > -      kind = CPTK_##CODE;             \
> > > > -      binary = (ARITY == 2);          \
> > > > -      variadic = (ARITY == -1);               \
> > > > -      type = (TCC == tcc_type);               \
> > > > -      break;
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -    default:
> > > > -      gcc_unreachable ();
> > > > -    }
> > > > +  const bool binary = (trait->arity == 2);
> > > > +  const bool variadic = (trait->arity == -1);
> > > >
> > > >    /* Get location of initial token.  */
> > > >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >    cp_lexer_consume_token (parser->lexer);
> > > >
> > > >    matching_parens parens;
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> > > >    else
> > > >      parens.require_open (parser);
> > > >
> > > > -  if (kind == CPTK_IS_DEDUCIBLE)
> > > > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> > > >      {
> > > >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > > >        type1 = cp_parser_id_expression (parser,
> > > > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >                                      /*optional_p=*/false);
> > > >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > > >      }
> > > > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      /* __type_pack_element takes an expression as its first argument and uses
> > > >         template-id syntax instead of function call syntax (for consistency
> > > >         with Clang).  We special case these properties of __type_pack_element
> > > > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >    if (type1 == error_mark_node)
> > > >      return error_mark_node;
> > > >
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      {
> > > >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > > >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >      }
> > > >
> > > >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      /* cp_parser_enclosed_template_argument_list above already took care
> > > >         of parsing the closing '>'.  */;
> > > >    else
> > > > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >
> > > >    /* Complete the trait expression, which may mean either processing
> > > >       the trait expr now or saving it for template instantiation.  */
> > > > -  switch (kind)
> > > > +  switch (trait->kind)
> > > >      {
> > > >      case CPTK_BASES:
> > > >        return cp_expr (finish_bases (type1, false), trait_loc);
> > > >      case CPTK_DIRECT_BASES:
> > > >        return cp_expr (finish_bases (type1, true), trait_loc);
> > > >      default:
> > > > -      if (type)
> > > > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > > +      if (trait->type)
> > > > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > > >        else
> > > > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > > > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > > >      }
> > > >  }
> > > >
> > > > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > > >
> > > >        return type;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > -      type = cp_parser_trait (parser, token->keyword);
> > > > +    default:
> > > > +      break;
> > > > +    }
> > > > +
> > > > +  /* If token is a type-yielding built-in traits, parse it.  */
> > > > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > > +  if (trait)
> > > > +    {
> > > > +      type = cp_parser_trait (parser, trait);
> > > >        if (decl_specs)
> > > >       cp_parser_set_decl_spec_type (decl_specs, type,
> > > >                                     token,
> > > >                                     /*type_definition_p=*/false);
> > > >
> > > >        return type;
> > > > -
> > > > -    default:
> > > > -      break;
> > > >      }
> > > >
> > > >    /* If token is an already-parsed decltype not followed by ::,
> > > > --
> > > > 2.42.0
> > > >
> > > >
> > >
> >
> >

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 00/40] Optimize type traits performance
  2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
                                 ` (39 preceding siblings ...)
  2023-10-13 22:37               ` [PATCH v19 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-16  0:09               ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 01/40] c++: Sort built-in traits alphabetically Ken Matsui
                                   ` (40 more replies)
  40 siblings, 41 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (40):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize is_const trait performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize is_volatile trait performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize is_array trait performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize is_unbounded_array trait performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize is_bounded_array trait performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize is_scoped_enum trait performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize is_member_pointer trait performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize is_member_function_pointer trait performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize is_member_object_pointer trait performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize is_reference trait performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize is_function trait performance
  libstdc++: Optimize is_object trait performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize remove_pointer trait performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize is_pointer trait performance
  c++: Implement __is_arithmetic built-in trait
  libstdc++: Optimize is_arithmetic trait performance
  libstdc++: Optimize is_fundamental trait performance
  libstdc++: Optimize is_compound trait performance
  c++: Implement __is_unsigned built-in trait
  libstdc++: Optimize is_unsigned trait performance
  c++: Implement __is_signed built-in trait
  libstdc++: Optimize is_signed trait performance
  c++: Implement __is_scalar built-in trait
  libstdc++: Optimize is_scalar trait performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/constraint.cc			       | 112 +++++--
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait.def			       |  27 +-
 gcc/cp/cp-tree.h			       |  31 +-
 gcc/cp/lex.cc				       |  21 ++
 gcc/cp/parser.cc			       | 153 +++++++---
 gcc/cp/semantics.cc			       | 157 +++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 117 ++++++--
 gcc/testsuite/g++.dg/ext/is_arithmetic.C      |  33 ++
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scalar.C	       |  31 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++
 gcc/testsuite/g++.dg/ext/is_signed.C	       |  47 +++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 +++
 gcc/testsuite/g++.dg/ext/is_unsigned.C        |  47 +++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 ++++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 284 ++++++++++++++++--
 29 files changed, 1376 insertions(+), 205 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 01/40] c++: Sort built-in traits alphabetically
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16 15:16                   ` Patrick Palka
  2023-10-16  0:09                 ` [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                   ` (39 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9e4e7043cd..722fc334e6f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 80ef1364e33..782aa515da0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 01/40] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16 14:55                   ` Patrick Palka
  2023-10-16  0:09                 ` [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
                                   ` (38 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses the identifier node to look up the specific trait.  Rather
than holding traits as keywords, we set all trait identifiers as cik_trait,
which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (init_cp_traits): New function to set cik_trait for all
	built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_traits): Define its values, declared in cp-tree.h.
	(cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 --
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  31 ++++++---
 gcc/cp/lex.cc             |  21 ++++++
 gcc/cp/parser.cc          | 141 ++++++++++++++++++++++++--------------
 6 files changed, 139 insertions(+), 74 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e34952da99..583abb2e79a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1375,16 +1381,25 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  short arity;
+  cp_trait_kind kind;
+  bool type;
+};
+
+/* The trait table.  */
+extern const struct cp_trait cp_traits[];
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..16a82a12a02 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  id = get_identifier (NAME); \
+  IDENTIFIER_CP_INDEX (id) = CPTK_##CODE; \
+  set_identifier_kind (id, cik_trait);
+#include "cp/cp-trait.def"
+#undef DEFTRAIT
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +344,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f3abae716fe..eba5272be03 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -279,6 +285,19 @@ static FILE *cp_lexer_debug_stream;
    sizeof, typeof, or alignof.  */
 int cp_unevaluated_operand;
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { ARITY, CPTK_##CODE, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(ARRAY_SIZE (cp_traits) <= 255,
+              "cp_traits array cannot have more than 255 entries");
+
 /* Dump up to NUM tokens in BUFFER to FILE starting with token
    START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
    first token in BUFFER.  If NUM is 0, dump all the tokens.  If
@@ -1167,12 +1186,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1195,48 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  tree id = token->u.value;
+
+  if (token->type == CPP_NAME
+      && TREE_CODE (id) == IDENTIFIER_NODE
+      && IDENTIFIER_TRAIT_P (id))
+    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1245,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2911,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6021,12 +6078,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6065,6 +6116,12 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      {
+	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	if (trait)
+	  return cp_parser_trait (parser, trait);
+      }
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11033,28 +11090,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11103,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   cp_lexer_consume_token (parser->lexer);
 
   matching_parens parens;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     cp_parser_require (parser, CPP_LESS, RT_LESS);
   else
     parens.require_open (parser);
 
-  if (kind == CPTK_IS_DEDUCIBLE)
+  if (trait->kind == CPTK_IS_DEDUCIBLE)
     {
       const cp_token* token = cp_lexer_peek_token (parser->lexer);
       type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11119,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 				       /*optional_p=*/false);
       type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
     }
-  else if (kind == CPTK_TYPE_PACK_ELEMENT)
+  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* __type_pack_element takes an expression as its first argument and uses
        template-id syntax instead of function call syntax (for consistency
        with Clang).  We special case these properties of __type_pack_element
@@ -11094,7 +11134,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
       tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11184,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
     }
 
   location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (kind == CPTK_TYPE_PACK_ELEMENT)
+  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
     /* cp_parser_enclosed_template_argument_list above already took care
        of parsing the closing '>'.  */;
   else
@@ -11158,17 +11198,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch (kind)
+  switch (trait->kind)
     {
     case CPTK_BASES:
       return cp_expr (finish_bases (type1, false), trait_loc);
     case CPTK_DIRECT_BASES:
       return cp_expr (finish_bases (type1, true), trait_loc);
     default:
-      if (type)
-	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+      if (trait->type)
+	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
       else
-	return finish_trait_expr (trait_loc, kind, type1, type2);
+	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
     }
 }
 
@@ -20081,20 +20121,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 01/40] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16 15:00                   ` Patrick Palka
  2023-10-16  0:09                 ` [PATCH v20 04/40] c++: Implement __is_const built-in trait Ken Matsui
                                   ` (37 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 48 ++++++++++++++++++++++++++++++------------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index eba5272be03..0f2a1baee6a 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1195,19 +1195,31 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  tree id = token->u.value;
+  tree id = token1->u.value;
 
-  if (token->type == CPP_NAME
+  if (token1->type == CPP_NAME
       && TREE_CODE (id) == IDENTIFIER_NODE
       && IDENTIFIER_TRAIT_P (id))
-    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (id)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
 
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
+
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1215,9 +1227,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1228,9 +1240,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1245,7 +1257,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6117,7 +6129,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	 keyword.  */
     case CPP_NAME:
       {
-	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+	const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer, token);
 	if (trait)
 	  return cp_parser_trait (parser, trait);
       }
@@ -20126,7 +20138,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 04/40] c++: Implement __is_const built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (2 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
                                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 722fc334e6f..567dd35fe0a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 782aa515da0..23f1d1c249a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 05/40] libstdc++: Optimize is_const trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (3 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 04/40] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
                                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_const trait by dispatching to
the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 06/40] c++: Implement __is_volatile built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (4 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
                                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 567dd35fe0a..f031e022541 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 23f1d1c249a..73178540fbd 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 07/40] libstdc++: Optimize is_volatile trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (5 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 08/40] c++: Implement __is_array built-in trait Ken Matsui
                                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_volatile trait by dispatching
to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 08/40] c++: Implement __is_array built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (6 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
                                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f031e022541..5e30a4a907a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73178540fbd..e1358afcb3f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 09/40] libstdc++: Optimize is_array trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (7 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 08/40] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_array trait by dispatching to
the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 10/40] c++: Implement __is_unbounded_array built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (8 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
                                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5e30a4a907a..751ac61b25a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3796,6 +3796,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e1358afcb3f..0a2699be476 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 11/40] libstdc++: Optimize is_unbounded_array trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (9 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unbounded_array trait by
dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 12/40] c++: Implement __is_bounded_array built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (10 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
                                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 751ac61b25a..d09252a56b6 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3723,6 +3723,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0a2699be476..32880754020 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 13/40] libstdc++: Optimize is_bounded_array trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (11 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_bounded_array trait by
dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 14/40] c++: Implement __is_scoped_enum built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (12 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:09                 ` [PATCH v20 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
                                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d09252a56b6..1c0b2e0f178 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 32880754020..f56ab031d5f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 15/40] libstdc++: Optimize is_scoped_enum trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (13 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-16  0:09                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:09 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scoped_enum trait
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 16/40] c++: Implement __is_member_pointer built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (14 preceding siblings ...)
  2023-10-16  0:09                 ` [PATCH v20 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
                                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1c0b2e0f178..f0d3f89464c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f56ab031d5f..6c4880d8a33 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 17/40] libstdc++: Optimize is_member_pointer trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (15 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_pointer trait
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 18/40] c++: Implement __is_member_function_pointer built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (16 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
                                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f0d3f89464c..d0464dd4f6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3756,6 +3756,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6c4880d8a33..4d521f87bbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 19/40] libstdc++: Optimize is_member_function_pointer trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (17 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_function_pointer trait
by dispatching to the new __is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 20/40] c++: Implement __is_member_object_pointer built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (18 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
                                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d0464dd4f6a..98b1f004a68 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3759,6 +3759,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4d521f87bbb..9cbb434d4c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 21/40] libstdc++: Optimize is_member_object_pointer trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (19 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 22/40] c++: Implement __is_reference built-in trait Ken Matsui
                                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_member_object_pointer trait
by dispatching to the new __is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 22/40] c++: Implement __is_reference built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (20 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
                                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 98b1f004a68..5cdb59d174e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9cbb434d4c2..df720459458 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 23/40] libstdc++: Optimize is_reference trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (21 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 22/40] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 24/40] c++: Implement __is_function built-in trait Ken Matsui
                                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_reference trait by dispatching
to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 24/40] c++: Implement __is_function built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (22 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
                                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 5cdb59d174e..99a7e7247ce 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3750,6 +3750,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index df720459458..4b8e80f3e62 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 25/40] libstdc++: Optimize is_function trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (23 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 24/40] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 26/40] libstdc++: Optimize is_object " Ken Matsui
                                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_function trait by dispatching
to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 26/40] libstdc++: Optimize is_object trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (24 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16 18:04                   ` Patrick Palka
  2023-10-16  0:10                 ` [PATCH v20 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
                                   ` (14 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_object trait by dispatching to
the new __is_function and __is_reference built-in traits.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_function and
	__is_reference built-in traits.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..674d398c075 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
+                             || is_void<_Tp>::value)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3314,17 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
+ && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_object_v
+    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 27/40] c++: Implement __remove_pointer built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (25 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
                                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..2add97ae749 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -97,6 +97,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 4b8e80f3e62..168411f6700 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12488,6 +12488,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..bcab0599d1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -173,6 +173,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 28/40] libstdc++: Optimize remove_pointer trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (26 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
                                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the remove_pointer trait by
dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 674d398c075..9c56d15c0b7 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2105,6 +2105,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2113,11 +2119,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 29/40] c++: Implement __is_pointer built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (27 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
                                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C    | 51 ++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 99a7e7247ce..c9d627fa782 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3787,6 +3787,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2add97ae749..c60724e869e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 168411f6700..83ed674b9d4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12412,6 +12415,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index bcab0599d1a..efce04fd09d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (28 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16 16:36                   ` Patrick Palka
  2023-10-16  0:10                 ` [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
                                   ` (10 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the performance of the is_pointer trait by dispatching to
the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..cd5ce45951f 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if __has_builtin(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 9c56d15c0b7..3acd843f2f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (29 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16 17:16                   ` Patrick Palka
  2023-10-16  0:10                 ` [PATCH v20 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
                                   ` (9 subsequent siblings)
  40 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_arithmetic.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
	* g++.dg/ext/is_arithmetic.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_arithmetic.C | 33 ++++++++++++++++++++++++
 5 files changed, 44 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c9d627fa782..3a7f968eae8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARITHMETIC:
+      inform (loc, "  %qT is not an arithmetic type", t1);
+      break;
     case CPTK_IS_ARRAY:
       inform (loc, "  %qT is not an array", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index c60724e869e..b2be7b7bbd7 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 83ed674b9d4..deab0134509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARITHMETIC:
+      return ARITHMETIC_TYPE_P (type1);
+
     case CPTK_IS_ARRAY:
       return type_code1 == ARRAY_TYPE;
 
@@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARITHMETIC:
     case CPTK_IS_ARRAY:
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index efce04fd09d..4bc85f4babb 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_arithmetic)
+# error "__has_builtin (__is_arithmetic) failed"
+#endif
 #if !__has_builtin (__is_array)
 # error "__has_builtin (__is_array) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
new file mode 100644
index 00000000000..fd35831f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
@@ -0,0 +1,33 @@
+// { 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_arithmetic, void, false);
+
+SA_TEST_CATEGORY(__is_arithmetic, char, true);
+SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
+SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
+SA_TEST_CATEGORY(__is_arithmetic, short, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
+SA_TEST_CATEGORY(__is_arithmetic, int, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
+SA_TEST_CATEGORY(__is_arithmetic, long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
+SA_TEST_CATEGORY(__is_arithmetic, long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
+SA_TEST_CATEGORY(__is_arithmetic, float, true);
+SA_TEST_CATEGORY(__is_arithmetic, double, true);
+SA_TEST_CATEGORY(__is_arithmetic, long double, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 32/40] libstdc++: Optimize is_arithmetic trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (30 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
                                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_arithmetic trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_arithmetic): Use __is_arithmetic
	built-in trait.
	(is_arithmetic_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 3acd843f2f2..cc466e0f606 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -726,10 +726,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_arithmetic
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_arithmetic
+    : public __bool_constant<__is_arithmetic(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_arithmetic
     : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
     { };
+#endif
 
   /// is_fundamental
   template<typename _Tp>
@@ -3344,8 +3351,14 @@ template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+template <typename _Tp>
+  inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 33/40] libstdc++: Optimize is_fundamental trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (31 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 34/40] libstdc++: Optimize is_compound " Ken Matsui
                                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_fundamental trait by
dispatching to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_fundamental_v): Use __is_arithmetic
	built-in trait.
	(is_fundamental): Likewise. Optimize the original implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cc466e0f606..88171e1a672 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -739,11 +739,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_fundamental
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
+  template<typename _Tp>
+    struct is_fundamental
+    : public __bool_constant<__is_arithmetic(_Tp)
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
+    { };
+#else
   template<typename _Tp>
     struct is_fundamental
-    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
-		   is_null_pointer<_Tp>>::type
+    : public __bool_constant<is_arithmetic<_Tp>::value
+                             || is_void<_Tp>::value
+                             || is_null_pointer<_Tp>::value>
     { };
+#endif
 
   /// is_object
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
@@ -3354,13 +3364,15 @@ template <typename _Tp>
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_arithmetic)
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = __is_arithmetic(_Tp);
+template <typename _Tp>
+  inline constexpr bool is_fundamental_v
+    = __is_arithmetic(_Tp) || is_void_v<_Tp> || is_null_pointer_v<_Tp>;
 #else
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
-#endif
-
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
  && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 34/40] libstdc++: Optimize is_compound trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (32 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
                                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_compound trait by dispatching
to the new __is_arithmetic built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_compound): Do not use __not_.
	(is_compound_v): Use is_fundamental_v instead.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 88171e1a672..48d630a1478 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// is_compound
   template<typename _Tp>
     struct is_compound
-    : public __not_<is_fundamental<_Tp>>::type { };
+    : public __bool_constant<!is_fundamental<_Tp>::value> { };
 
   /// is_member_pointer
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
@@ -3387,7 +3387,7 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-  inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+  inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 35/40] c++: Implement __is_unsigned built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (33 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 34/40] libstdc++: Optimize is_compound " Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
                                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unsigned.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unsigned.
	* g++.dg/ext/is_unsigned.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unsigned.C   | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unsigned.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 3a7f968eae8..c28dad702c3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3829,6 +3829,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_UNSIGNED:
+      inform (loc, "  %qT is not an unsigned type", t1);
+      break;
     case CPTK_IS_VOLATILE:
       inform (loc, "  %qT is not a volatile type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b2be7b7bbd7..0603b4a230f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -94,6 +94,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
+DEFTRAIT_EXPR (IS_UNSIGNED, "__is_unsigned", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index deab0134509..14387821b85 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12250,6 +12250,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_UNSIGNED:
+      return TYPE_UNSIGNED (type1);
+
     case CPTK_IS_VOLATILE:
       return CP_TYPE_VOLATILE_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
+    case CPTK_IS_UNSIGNED:
     case CPTK_IS_VOLATILE:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4bc85f4babb..3d380f94b06 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -164,6 +164,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_unsigned)
+# error "__has_builtin (__is_unsigned) failed"
+#endif
 #if !__has_builtin (__is_volatile)
 # error "__has_builtin (__is_volatile) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unsigned.C b/gcc/testsuite/g++.dg/ext/is_unsigned.C
new file mode 100644
index 00000000000..2bb45d209a7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unsigned.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_unsigned, void, false);
+
+SA_TEST_CATEGORY(__is_unsigned, bool, (bool(-1) > bool(0)));
+SA_TEST_CATEGORY(__is_unsigned, char, (char(-1) > char(0)));
+SA_TEST_CATEGORY(__is_unsigned, signed char, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned char, true);
+SA_TEST_CATEGORY(__is_unsigned, wchar_t, (wchar_t(-1) > wchar_t(0)));
+SA_TEST_CATEGORY(__is_unsigned, short, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned short, true);
+SA_TEST_CATEGORY(__is_unsigned, int, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned int, true);
+SA_TEST_CATEGORY(__is_unsigned, long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long, true);
+SA_TEST_CATEGORY(__is_unsigned, long long, false);
+SA_TEST_CATEGORY(__is_unsigned, unsigned long long, true);
+
+SA_TEST_CATEGORY(__is_unsigned, float, false);
+SA_TEST_CATEGORY(__is_unsigned, double, false);
+SA_TEST_CATEGORY(__is_unsigned, long double, false);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_unsigned, unsigned __int128, true);
+SA_TEST_CATEGORY(__is_unsigned, __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_unsigned, __float128, false);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unsigned, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 36/40] libstdc++: Optimize is_unsigned trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (34 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 37/40] c++: Implement __is_signed built-in trait Ken Matsui
                                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_unsigned trait by dispatching
to the new __is_unsigned built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unsigned): Use __is_unsigned built-in
	trait.
	(is_unsigned_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 48d630a1478..f7d3815f332 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1001,10 +1001,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_unsigned
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+  template<typename _Tp>
+    struct is_unsigned
+    : public __bool_constant<__is_unsigned(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_unsigned
     : public __and_<is_arithmetic<_Tp>, __not_<is_signed<_Tp>>>::type
     { };
+#endif
 
   /// @cond undocumented
   template<typename _Tp, typename _Up = _Tp&&>
@@ -3440,8 +3447,14 @@ template <typename _Tp>
 
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
+template <typename _Tp>
+  inline constexpr bool is_unsigned_v = __is_unsigned(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value;
+#endif
 
 template <typename _Tp, typename... _Args>
   inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 37/40] c++: Implement __is_signed built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (35 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
                                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_signed.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_signed.
	* g++.dg/ext/is_signed.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_signed.C     | 47 ++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_signed.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c28dad702c3..b161c9b2c9e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SIGNED:
+      inform (loc, "  %qT is not a signed type", t1);
+      break;
     case CPTK_IS_SCOPED_ENUM:
       inform (loc, "  %qT is not a scoped enum", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0603b4a230f..b0faa4c8937 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 14387821b85..5e6b2ca37ac 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SIGNED:
+      return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
+
     case CPTK_IS_SCOPED_ENUM:
       return SCOPED_ENUM_P (type1);
 
@@ -12425,6 +12428,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 3d380f94b06..aaf7254df4b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_signed)
+# error "__has_builtin (__is_signed) failed"
+#endif
 #if !__has_builtin (__is_scoped_enum)
 # error "__has_builtin (__is_scoped_enum) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_signed.C b/gcc/testsuite/g++.dg/ext/is_signed.C
new file mode 100644
index 00000000000..a04b548105d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_signed.C
@@ -0,0 +1,47 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_signed, void, false);
+
+SA_TEST_CATEGORY(__is_signed, bool, bool(-1) < bool(0));
+SA_TEST_CATEGORY(__is_signed, char, char(-1) < char(0));
+SA_TEST_CATEGORY(__is_signed, signed char, true);
+SA_TEST_CATEGORY(__is_signed, unsigned char, false);
+SA_TEST_CATEGORY(__is_signed, wchar_t, wchar_t(-1) < wchar_t(0));
+SA_TEST_CATEGORY(__is_signed, short, true);
+SA_TEST_CATEGORY(__is_signed, unsigned short, false);
+SA_TEST_CATEGORY(__is_signed, int, true);
+SA_TEST_CATEGORY(__is_signed, unsigned int, false);
+SA_TEST_CATEGORY(__is_signed, long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long, false);
+SA_TEST_CATEGORY(__is_signed, long long, true);
+SA_TEST_CATEGORY(__is_signed, unsigned long long, false);
+
+SA_TEST_CATEGORY(__is_signed, float, true);
+SA_TEST_CATEGORY(__is_signed, double, true);
+SA_TEST_CATEGORY(__is_signed, long double, true);
+
+#ifndef __STRICT_ANSI__
+// GNU Extensions.
+#ifdef __SIZEOF_INT128__
+SA_TEST_CATEGORY(__is_signed, __int128, true);
+SA_TEST_CATEGORY(__is_signed, unsigned __int128, false);
+#endif
+
+#ifdef _GLIBCXX_USE_FLOAT128
+SA_TEST_CATEGORY(__is_signed, __float128, true);
+#endif
+#endif
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_signed, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 38/40] libstdc++: Optimize is_signed trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (36 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 37/40] c++: Implement __is_signed built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
                                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_signed trait by dispatching to
the new __is_signed built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_signed): Use __is_signed built-in trait.
	(is_signed_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index f7d3815f332..7e93923f44b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -982,6 +982,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<__is_abstract(_Tp)>
     { };
 
+  /// is_signed
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+  template<typename _Tp>
+    struct is_signed
+    : public __bool_constant<__is_signed(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp,
 	   bool = is_arithmetic<_Tp>::value>
@@ -994,11 +1001,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
   /// @endcond
 
-  /// is_signed
   template<typename _Tp>
     struct is_signed
     : public __is_signed_helper<_Tp>::type
     { };
+#endif
 
   /// is_unsigned
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
@@ -3445,8 +3452,13 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_final_v = __is_final(_Tp);
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_signed)
+template <typename _Tp>
+  inline constexpr bool is_signed_v = __is_signed(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_signed_v = is_signed<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unsigned)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 39/40] c++: Implement __is_scalar built-in trait
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (37 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-16  0:10                 ` [PATCH v20 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scalar.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scalar.
	* g++.dg/ext/is_scalar.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scalar.C     | 31 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scalar.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b161c9b2c9e..78f100d2745 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3802,6 +3802,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCALAR:
+      inform (loc, "  %qT is not a scalar type", t1);
+      break;
     case CPTK_IS_SIGNED:
       inform (loc, "  %qT is not a signed type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b0faa4c8937..08a2780c929 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -86,6 +86,7 @@ DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCALAR, "__is_scalar", 1)
 DEFTRAIT_EXPR (IS_SIGNED, "__is_signed", 1)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5e6b2ca37ac..be345f9aa47 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12226,6 +12226,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCALAR:
+      return SCALAR_TYPE_P (type1);
+
     case CPTK_IS_SIGNED:
       return ARITHMETIC_TYPE_P (type1) && TYPE_SIGN (type1) == SIGNED;
 
@@ -12428,6 +12431,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCALAR:
     case CPTK_IS_SIGNED:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index aaf7254df4b..f4f6fed6876 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -140,6 +140,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scalar)
+# error "__has_builtin (__is_scalar) failed"
+#endif
 #if !__has_builtin (__is_signed)
 # error "__has_builtin (__is_signed) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scalar.C b/gcc/testsuite/g++.dg/ext/is_scalar.C
new file mode 100644
index 00000000000..457fddc52fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scalar.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <cstddef>  // std::nullptr_t
+#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)
+
+// volatile return type would cause a warning.
+#define SA_FN_TEST_CATEGORY(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+SA_TEST_CATEGORY(__is_scalar, int, true);
+SA_TEST_CATEGORY(__is_scalar, float, true);
+SA_TEST_CATEGORY(__is_scalar, EnumType, true);
+SA_TEST_CATEGORY(__is_scalar, int*, true);
+SA_FN_TEST_CATEGORY(__is_scalar, int(*)(int), true);
+SA_TEST_CATEGORY(__is_scalar, int (ClassType::*), true);
+SA_FN_TEST_CATEGORY(__is_scalar, int (ClassType::*) (int), true);
+SA_TEST_CATEGORY(__is_scalar, std::nullptr_t, true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_scalar, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v20 40/40] libstdc++: Optimize is_scalar trait performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (38 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
@ 2023-10-16  0:10                 ` Ken Matsui
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
  40 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16  0:10 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the performance of the is_scalar trait by dispatching to
the new __is_scalar built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scalar): Use __is_scalar built-in
	trait.
	(is_scalar_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7e93923f44b..eb16a642575 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -775,11 +775,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_pointer;
 
   /// is_scalar
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+  template<typename _Tp>
+    struct is_scalar
+    : public __bool_constant<__is_scalar(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_scalar
     : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                    is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
     { };
+#endif
 
   /// is_compound
   template<typename _Tp>
@@ -3398,8 +3405,14 @@ template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scalar)
+template <typename _Tp>
+  inline constexpr bool is_scalar_v = __is_scalar(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_compound_v = !is_fundamental_v<_Tp>;
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node
  2023-10-16  0:09                 ` [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-16 14:55                   ` Patrick Palka
  2023-10-16 19:57                     ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 14:55 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Patrick Palka

On Sun, 15 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.

Thanks, this looks great!  Some review comments below.

> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Remove all mappings of
> 	built-in traits.
> 	* c-common.h (enum rid): Remove all RID values for built-in traits.
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
> 	cases for built-in traits.  Check for built-in traits via
> 	the new cik_trait kind.
> 	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
> 	addr_space_t.
> 	(struct cp_trait): New struct to hold trait information.
> 	(cp_traits): New array to hold a mapping to all traits.
> 	(cik_reserved_for_udlit): Rename to ...
> 	(cik_trait): ... this.
> 	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> 	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> 	* lex.cc (init_cp_traits): New function to set cik_trait for all
> 	built-in trait identifiers.

We should mention setting IDENTIFIER_CP_INDEX as well.

> 	(cxx_init): Call init_cp_traits function.
> 	* parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> 	(cp_lexer_lookup_trait): New function to look up a
> 	built-in trait by IDENTIFIER_CP_INDEX.
> 	(cp_lexer_lookup_trait_expr): Likewise, look up an
> 	expression-yielding built-in trait.
> 	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> 	built-in trait.
> 	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> 	for built-in traits.
> 	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
> 	type-yielding built-in traits.
> 	(cp_parser_primary_expression): Remove all RID value cases for
> 	built-in traits.  Handle expression-yielding built-in traits.
> 	(cp_parser_trait): Handle cp_trait instead of enum rid.
> 	(cp_parser_simple_type_specifier): Remove all RID value cases
> 	for built-in traits.  Handle type-yielding built-in traits.
> 
> Co-authored-by: Patrick Palka <ppalka@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |   7 --
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h          |  31 ++++++---
>  gcc/cp/lex.cc             |  21 ++++++
>  gcc/cp/parser.cc          | 141 ++++++++++++++++++++++++--------------
>  6 files changed, 139 insertions(+), 74 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",		RID_WCHAR,	D_CXXONLY },
>    { "while",		RID_WHILE,	0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,		RID_##CODE,	D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
> -
>    /* C++ transactional memory.  */
>    { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>    { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
>  	}
>      }
>  
> +  /* Check for built-in traits.  */
> +  if (IDENTIFIER_TRAIT_P (id))
> +    return true;
> +
>    /* Also detect common reserved C++ words that aren't strictly built-in
>       functions.  */
>    switch (C_RID_CODE (id))
> @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 6e34952da99..583abb2e79a 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
>    cik_simple_op = 4,	/* Non-assignment operator name.  */
>    cik_assign_op = 5,	/* An assignment operator name.  */
>    cik_conv_op = 6,	/* Conversion operator name.  */
> -  cik_reserved_for_udlit = 7,	/* Not yet in use  */
> +  cik_trait = 7,	/* Built-in trait name.  */
>    cik_max
>  };
>  
> @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
>      & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is for any operator name (including
> -   conversions).  Value 4, 5, 6 or 7.  */
> +   conversions).  Value 4, 5, or 6.  */
>  #define IDENTIFIER_ANY_OP_P(NODE)		\
> -  (IDENTIFIER_KIND_BIT_2 (NODE))
> +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
>  
>  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
>  #define IDENTIFIER_OVL_OP_P(NODE)		\
> @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
>     & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is the name of a type-conversion
> -   operator.  Value 7.  */
> +   operator.  Value 6.  */
>  #define IDENTIFIER_CONV_OP_P(NODE)		\
>    (IDENTIFIER_ANY_OP_P (NODE)			\
>     & IDENTIFIER_KIND_BIT_1 (NODE)		\
>     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
>  
> +/* True if this identifier is the name of a built-in trait.  */
> +#define IDENTIFIER_TRAIT_P(NODE)		\
> +  (IDENTIFIER_KIND_BIT_0 (NODE)			\
> +   && IDENTIFIER_KIND_BIT_1 (NODE)		\
> +   && IDENTIFIER_KIND_BIT_2 (NODE))
> +
>  /* True if this identifier is a new or delete operator.  */
>  #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
>    (IDENTIFIER_OVL_OP_P (NODE)			\
> @@ -1375,16 +1381,25 @@ struct GTY (()) tree_argument_pack_select {
>    int index;
>  };
>  
> -/* The different kinds of traits that we encounter.  */
> -
> -enum cp_trait_kind
> -{
> +/* The different kinds of traits that we encounter.  The size is limited to
> +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> +enum cp_trait_kind : addr_space_t {
>  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
>    CPTK_##CODE,
>  #include "cp-trait.def"
>  #undef DEFTRAIT
>  };
>  
> +/* The trait type.  */
> +struct cp_trait {
> +  short arity;
> +  cp_trait_kind kind;
> +  bool type;

Could we also store the const char* name of each trait here, so that ...

> +};
> +
> +/* The trait table.  */
> +extern const struct cp_trait cp_traits[];
> +
>  /* The types that we are processing.  */
>  #define TRAIT_EXPR_TYPE1(NODE) \
>    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..16a82a12a02 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>  
>  static int interface_strcmp (const char *);
> +static void init_cp_traits (void);
>  static void init_cp_pragma (void);
>  
>  static tree parse_strconst_pragma (const char *, int);
> @@ -283,6 +284,25 @@ init_reswords (void)
>      }
>  }
>  
> +/* Initialize the C++ traits.  */
> +static void
> +init_cp_traits (void)
> +{
> +  tree id;
> +
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> +  id = get_identifier (NAME); \
> +  IDENTIFIER_CP_INDEX (id) = CPTK_##CODE; \
> +  set_identifier_kind (id, cik_trait);
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT

... we could replace this straight-line code with a loop over cp_traits?
It'd make cp_traits bigger but init_cp_traits should get much smaller,
which should be a net win in terms of binary size.

> +
> +  /* An alias for __is_same.  */
> +  id = get_identifier ("__is_same_as");
> +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> +  set_identifier_kind (id, cik_trait);
> +}
> +
>  static void
>  init_cp_pragma (void)
>  {
> @@ -324,6 +344,7 @@ cxx_init (void)
>    input_location = BUILTINS_LOCATION;
>  
>    init_reswords ();
> +  init_cp_traits ();
>    init_tree ();
>    init_cp_semantics ();
>    init_operators ();
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index f3abae716fe..eba5272be03 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
> +static const cp_trait *cp_lexer_lookup_trait
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_expr
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_type
> +  (const cp_token *);
>  
>  static cp_token_cache *cp_token_cache_new
>    (cp_token *, cp_token *);
> @@ -279,6 +285,19 @@ static FILE *cp_lexer_debug_stream;
>     sizeof, typeof, or alignof.  */
>  int cp_unevaluated_operand;
>  
> +/* The trait table, declared in cp-tree.h.  */
> +const cp_trait cp_traits[] =
> +{
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> +  { ARITY, CPTK_##CODE, (TCC == tcc_type) },
> +#include "cp-trait.def"
> +#undef DEFTRAIT
> +};
> +/* The trait table cannot have more than 255 (addr_space_t) entries since
> +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> +              "cp_traits array cannot have more than 255 entries");
> +
>  /* Dump up to NUM tokens in BUFFER to FILE starting with token
>     START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
>     first token in BUFFER.  If NUM is 0, dump all the tokens.  If
> @@ -1167,12 +1186,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      case RID_CONSTEVAL:
>        return true;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      return true;
> -
>      default:
>        if (keyword >= RID_FIRST_INT_N
>  	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> @@ -1182,6 +1195,48 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      }
>  }
>  
> +/* Look ups the corresponding built-in trait if a given token is
> +   a built-in trait.  Otherwise, returns nullptr.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait (const cp_token *token)
> +{
> +  tree id = token->u.value;
> +
> +  if (token->type == CPP_NAME
> +      && TREE_CODE (id) == IDENTIFIER_NODE

The value of a CPP_NAME token is always an IDENTIFIER_NODE, so this
check should be redundant.  Also we should access the u.value union member
only after the CPP_NAME check, since for some other token kinds u.value
isn't the active member (and reading from it would be undefined behavior
strictly speaking).

> +      && IDENTIFIER_TRAIT_P (id))
> +    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is an expression-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_expr (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && !trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is a type-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_type (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
>  /* Return true if the next token is a keyword for a decl-specifier.  */
>  
>  static bool
> @@ -1190,6 +1245,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
>    cp_token *token;
>  
>    token = cp_lexer_peek_token (lexer);
> +  if (cp_lexer_lookup_trait_type (token))
> +    return true;
>    return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
>  
> @@ -2854,7 +2911,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, const cp_trait *);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6021,12 +6078,6 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_OFFSETOF:
>  	  return cp_parser_builtin_offsetof (parser);
>  
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -	case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -	  return cp_parser_trait (parser, token->keyword);
> -
>  	// C++ concepts
>  	case RID_REQUIRES:
>  	  return cp_parser_requires_expression (parser);
> @@ -6065,6 +6116,12 @@ cp_parser_primary_expression (cp_parser *parser,
>  	 `::' as the beginning of a qualified-id, or the "operator"
>  	 keyword.  */
>      case CPP_NAME:
> +      {
> +	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> +	if (trait)

A tiny nit, but we could remove the extra block scope here by doing
'if (const cp_trait* trait = ...)' instead.

> +	  return cp_parser_trait (parser, trait);
> +      }
> +      /* FALLTHRU */
>      case CPP_SCOPE:
>      case CPP_TEMPLATE_ID:
>      case CPP_NESTED_NAME_SPECIFIER:
> @@ -11033,28 +11090,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>  
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
>  {
> -  cp_trait_kind kind;
>    tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> -
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:			 \
> -      kind = CPTK_##CODE;		 \
> -      binary = (ARITY == 2);		 \
> -      variadic = (ARITY == -1);		 \
> -      type = (TCC == tcc_type);		 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  const bool binary = (trait->arity == 2);
> +  const bool variadic = (trait->arity == -1);

Could we continue defining the local variables 'kind' and 'type' here so
that we don't have to adjust their uses in the rest of the function?
That should yield a smaller diff for this function.

>  
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -11063,12 +11103,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    cp_lexer_consume_token (parser->lexer);
>  
>    matching_parens parens;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      cp_parser_require (parser, CPP_LESS, RT_LESS);
>    else
>      parens.require_open (parser);
>  
> -  if (kind == CPTK_IS_DEDUCIBLE)
> +  if (trait->kind == CPTK_IS_DEDUCIBLE)
>      {
>        const cp_token* token = cp_lexer_peek_token (parser->lexer);
>        type1 = cp_parser_id_expression (parser,
> @@ -11079,7 +11119,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  				       /*optional_p=*/false);
>        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
>      }
> -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* __type_pack_element takes an expression as its first argument and uses
>         template-id syntax instead of function call syntax (for consistency
>         with Clang).  We special case these properties of __type_pack_element
> @@ -11094,7 +11134,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>    if (type1 == error_mark_node)
>      return error_mark_node;
>  
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      {
>        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
>        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> @@ -11144,7 +11184,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>      }
>  
>    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
>      /* cp_parser_enclosed_template_argument_list above already took care
>         of parsing the closing '>'.  */;
>    else
> @@ -11158,17 +11198,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>  
>    /* Complete the trait expression, which may mean either processing
>       the trait expr now or saving it for template instantiation.  */
> -  switch (kind)
> +  switch (trait->kind)
>      {
>      case CPTK_BASES:
>        return cp_expr (finish_bases (type1, false), trait_loc);
>      case CPTK_DIRECT_BASES:
>        return cp_expr (finish_bases (type1, true), trait_loc);
>      default:
> -      if (type)
> -	return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> +      if (trait->type)
> +	return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
>        else
> -	return finish_trait_expr (trait_loc, kind, type1, type2);
> +	return finish_trait_expr (trait_loc, trait->kind, type1, type2);
>      }
>  }
>  
> @@ -20081,20 +20121,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>  
>        return type;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    default:
> +      break;
> +    }
> +
> +  /* If token is a type-yielding built-in traits, parse it.  */
> +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> +  if (trait)
> +    {
> +      type = cp_parser_trait (parser, trait);
>        if (decl_specs)
>  	cp_parser_set_decl_spec_type (decl_specs, type,
>  				      token,
>  				      /*type_definition_p=*/false);
>  
>        return type;
> -
> -    default:
> -      break;
>      }
>  
>    /* If token is an already-parsed decltype not followed by ::,
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers
  2023-10-16  0:09                 ` [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-16 15:00                   ` Patrick Palka
  0 siblings, 0 replies; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 15:00 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch accepts the use of built-in trait identifiers when they are
> actually not used as traits.  Specifically, we check if the subsequent token
> is '(' for ordinary built-in traits or is '<' only for the special
> __type_pack_element built-in trait.  If those identifiers are used
> differently, the parser treats them as normal identifiers.  This allows
> us to accept code like: struct __is_pointer {};.

LGTM, thanks

> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (cp_lexer_lookup_trait): Rename to ...
> 	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
> 	the corresponding built-in trait.
> 	(cp_lexer_lookup_trait_expr): Rename to ...
> 	(cp_lexer_peek_trait_expr): ... this.
> 	(cp_lexer_lookup_trait_type): Rename to ...
> 	(cp_lexer_peek_trait_type): ... this.
> 	(cp_lexer_next_token_is_decl_specifier_keyword): Call
> 	cp_lexer_peek_trait_type.
> 	(cp_parser_simple_type_specifier): Likewise.
> 	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/cp/parser.cc | 48 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 30 insertions(+), 18 deletions(-)
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index eba5272be03..0f2a1baee6a 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
> -static const cp_trait *cp_lexer_lookup_trait
> -  (const cp_token *);
> -static const cp_trait *cp_lexer_lookup_trait_expr
> -  (const cp_token *);
> -static const cp_trait *cp_lexer_lookup_trait_type
> -  (const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait
> +  (cp_lexer *lexer, const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait_expr
> +  (cp_lexer *lexer, const cp_token *);
> +static const cp_trait *cp_lexer_peek_trait_type
> +  (cp_lexer *lexer, const cp_token *);
>  
>  static cp_token_cache *cp_token_cache_new
>    (cp_token *, cp_token *);
> @@ -1195,19 +1195,31 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      }
>  }
>  
> -/* Look ups the corresponding built-in trait if a given token is
> +/* Peeks the corresponding built-in trait if a given token is
>     a built-in trait.  Otherwise, returns nullptr.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait (const cp_token *token)
> +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
>  {
> -  tree id = token->u.value;
> +  tree id = token1->u.value;
>  
> -  if (token->type == CPP_NAME
> +  if (token1->type == CPP_NAME
>        && TREE_CODE (id) == IDENTIFIER_NODE
>        && IDENTIFIER_TRAIT_P (id))
> -    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
> +    {
> +      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (id)];
> +      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
>  
> +      /* Check if the subsequent token is a `<' token to
> +         __type_pack_element or is a `(' token to everything else.  */
> +      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
> +      if (is_pack_element && token2->type != CPP_LESS)
> +	return nullptr;
> +      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
> +	return nullptr;
> +
> +      return &trait;
> +    }
>    return nullptr;
>  }
>  
> @@ -1215,9 +1227,9 @@ cp_lexer_lookup_trait (const cp_token *token)
>     built-in trait.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait_expr (const cp_token *token)
> +cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
>  {
> -  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
>    if (trait && !trait->type)
>      return trait;
>  
> @@ -1228,9 +1240,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
>     built-in trait.  */
>  
>  static const cp_trait *
> -cp_lexer_lookup_trait_type (const cp_token *token)
> +cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
>  {
> -  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
>    if (trait && trait->type)
>      return trait;
>  
> @@ -1245,7 +1257,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
>    cp_token *token;
>  
>    token = cp_lexer_peek_token (lexer);
> -  if (cp_lexer_lookup_trait_type (token))
> +  if (cp_lexer_peek_trait_type (lexer, token))
>      return true;
>    return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
> @@ -6117,7 +6129,7 @@ cp_parser_primary_expression (cp_parser *parser,
>  	 keyword.  */
>      case CPP_NAME:
>        {
> -	const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> +	const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer, token);
>  	if (trait)
>  	  return cp_parser_trait (parser, trait);
>        }
> @@ -20126,7 +20138,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>      }
>  
>    /* If token is a type-yielding built-in traits, parse it.  */
> -  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> +  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
>    if (trait)
>      {
>        type = cp_parser_trait (parser, trait);
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically
  2023-10-16  0:09                 ` [PATCH v20 01/40] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-16 15:16                   ` Patrick Palka
  2023-10-16 20:11                     ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 15:16 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch sorts built-in traits alphabetically for better code
> readability.

Hmm, I'm not sure if we still want/need this change with this current
approach.  IIUC gperf would sort the trait names when generating the
hash table code, and so we wanted a more consistent mapping from the
cp-trait.def file to the generated code.  But with this current
non-gperf approach I'm inclined to leave the existing ordering alone
for sake of simplicity, and I kind of like that in cp-trait.def we
currently group all expression-yielding traits together and all
type-yielding traits together; that seems like a more natural layout
than plain alphabetical sorting.

> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (diagnose_trait_expr): Sort built-in traits
> 	alphabetically.
> 	* cp-trait.def: Likewise.
> 	* semantics.cc (trait_expr_value): Likewise.
> 	(finish_trait_expr): Likewise.
> 	(finish_trait_type): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/cp/constraint.cc                     | 68 ++++++++---------
>  gcc/cp/cp-trait.def                      | 10 +--
>  gcc/cp/semantics.cc                      | 94 ++++++++++++------------
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
>  4 files changed, 121 insertions(+), 121 deletions(-)
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index c9e4e7043cd..722fc334e6f 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_HAS_TRIVIAL_DESTRUCTOR:
>        inform (loc, "  %qT is not trivially destructible", t1);
>        break;
> +    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> +      inform (loc, "  %qT does not have unique object representations", t1);
> +      break;
>      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
>        inform (loc, "  %qT does not have a virtual destructor", t1);
>        break;
>      case CPTK_IS_ABSTRACT:
>        inform (loc, "  %qT is not an abstract class", t1);
>        break;
> +    case CPTK_IS_AGGREGATE:
> +      inform (loc, "  %qT is not an aggregate", t1);
> +      break;
> +    case CPTK_IS_ASSIGNABLE:
> +      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> +      break;
>      case CPTK_IS_BASE_OF:
>        inform (loc, "  %qT is not a base of %qT", t1, t2);
>        break;
>      case CPTK_IS_CLASS:
>        inform (loc, "  %qT is not a class", t1);
>        break;
> +    case CPTK_IS_CONSTRUCTIBLE:
> +      if (!t2)
> +    inform (loc, "  %qT is not default constructible", t1);
> +      else
> +    inform (loc, "  %qT is not constructible from %qE", t1, t2);
> +      break;
> +    case CPTK_IS_CONVERTIBLE:
> +      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> +      break;
>      case CPTK_IS_EMPTY:
>        inform (loc, "  %qT is not an empty class", t1);
>        break;
> @@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_IS_LITERAL_TYPE:
>        inform (loc, "  %qT is not a literal type", t1);
>        break;
> +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> +      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> +      break;
> +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> +      if (!t2)
> +	inform (loc, "  %qT is not nothrow default constructible", t1);
> +      else
> +	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> +      break;
> +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> +	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> +      break;
>      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
>        inform (loc, "  %qT is not pointer-interconvertible base of %qT",
>  	      t1, t2);
> @@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_IS_TRIVIAL:
>        inform (loc, "  %qT is not a trivial type", t1);
>        break;
> -    case CPTK_IS_UNION:
> -      inform (loc, "  %qT is not a union", t1);
> -      break;
> -    case CPTK_IS_AGGREGATE:
> -      inform (loc, "  %qT is not an aggregate", t1);
> -      break;
> -    case CPTK_IS_TRIVIALLY_COPYABLE:
> -      inform (loc, "  %qT is not trivially copyable", t1);
> -      break;
> -    case CPTK_IS_ASSIGNABLE:
> -      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> -      break;
>      case CPTK_IS_TRIVIALLY_ASSIGNABLE:
>        inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
>        break;
> -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> -      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> -      break;
> -    case CPTK_IS_CONSTRUCTIBLE:
> -      if (!t2)
> -	inform (loc, "  %qT is not default constructible", t1);
> -      else
> -	inform (loc, "  %qT is not constructible from %qE", t1, t2);
> -      break;
>      case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
>        if (!t2)
>  	inform (loc, "  %qT is not trivially default constructible", t1);
>        else
>  	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
>        break;
> -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> -      if (!t2)
> -	inform (loc, "  %qT is not nothrow default constructible", t1);
> -      else
> -	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> -      break;
> -    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> -      inform (loc, "  %qT does not have unique object representations", t1);
> -      break;
> -    case CPTK_IS_CONVERTIBLE:
> -      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> +    case CPTK_IS_TRIVIALLY_COPYABLE:
> +      inform (loc, "  %qT is not trivially copyable", t1);
>        break;
> -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> -	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> +    case CPTK_IS_UNION:
> +      inform (loc, "  %qT is not a union", t1);
>        break;
>      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
>        inform (loc, "  %qT is not a reference that binds to a temporary "
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 8b7fece0cc8..0e48e64b8dd 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
>  DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
> -DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> -
>  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> -DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
>  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> -DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
>  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
> +
> +/* FIXME Added space to avoid direct usage in GCC 13.  */
> +DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
>  
>  /* These traits yield a type pack, not a type, and are represented by
>     cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 80ef1364e33..782aa515da0 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>  		      && classtype_has_nothrow_assign_or_copy_p (type1,
>  								 true))));
>  
> -    case CPTK_HAS_TRIVIAL_ASSIGN:
> -      /* ??? The standard seems to be missing the "or array of such a class
> -	 type" wording for this trait.  */
> -      type1 = strip_array_types (type1);
> -      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> -	      && (trivial_type_p (type1)
> -		    || (CLASS_TYPE_P (type1)
> -			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> -
>      case CPTK_HAS_NOTHROW_CONSTRUCTOR:
>        type1 = strip_array_types (type1);
>        return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
> @@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>  		  && maybe_instantiate_noexcept (t)
>  		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
>  
> -    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> -      type1 = strip_array_types (type1);
> -      return (trivial_type_p (type1)
> -	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> -
>      case CPTK_HAS_NOTHROW_COPY:
>        type1 = strip_array_types (type1);
>        return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
>  	      || (CLASS_TYPE_P (type1)
>  		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
>  
> +    case CPTK_HAS_TRIVIAL_ASSIGN:
> +      /* ??? The standard seems to be missing the "or array of such a class
> +	 type" wording for this trait.  */
> +      type1 = strip_array_types (type1);
> +      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> +	      && (trivial_type_p (type1)
> +		    || (CLASS_TYPE_P (type1)
> +			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> +
> +    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> +      type1 = strip_array_types (type1);
> +      return (trivial_type_p (type1)
> +	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> +
>      case CPTK_HAS_TRIVIAL_COPY:
>        /* ??? The standard seems to be missing the "or array of such a class
>  	 type" wording for this trait.  */
> @@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>  	      || (CLASS_TYPE_P (type1)
>  		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
>  
> -    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> -      return type_has_virtual_destructor (type1);
> -
>      case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
>        return type_has_unique_obj_representations (type1);
>  
> +    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> +      return type_has_virtual_destructor (type1);
> +
>      case CPTK_IS_ABSTRACT:
>        return ABSTRACT_CLASS_TYPE_P (type1);
>  
>      case CPTK_IS_AGGREGATE:
>        return CP_AGGREGATE_TYPE_P (type1);
>  
> +    case CPTK_IS_ASSIGNABLE:
> +      return is_xible (MODIFY_EXPR, type1, type2);
> +
>      case CPTK_IS_BASE_OF:
>        return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
>  	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
> @@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_CLASS:
>        return NON_UNION_CLASS_TYPE_P (type1);
>  
> +    case CPTK_IS_CONSTRUCTIBLE:
> +      return is_xible (INIT_EXPR, type1, type2);
> +
> +    case CPTK_IS_CONVERTIBLE:
> +      return is_convertible (type1, type2);
> +
>      case CPTK_IS_EMPTY:
>        return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
>  
> @@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_LITERAL_TYPE:
>        return literal_type_p (type1);
>  
> +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> +      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> +
> +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> +      return is_nothrow_xible (INIT_EXPR, type1, type2);
> +
> +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> +      return is_nothrow_convertible (type1, type2);
> +
>      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
>        return pointer_interconvertible_base_of_p (type1, type2);
>  
> @@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_UNION:
>        return type_code1 == UNION_TYPE;
>  
> -    case CPTK_IS_ASSIGNABLE:
> -      return is_xible (MODIFY_EXPR, type1, type2);
> -
> -    case CPTK_IS_CONSTRUCTIBLE:
> -      return is_xible (INIT_EXPR, type1, type2);
> -
> -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> -      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> -
> -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> -      return is_nothrow_xible (INIT_EXPR, type1, type2);
> -
> -    case CPTK_IS_CONVERTIBLE:
> -      return is_convertible (type1, type2);
> -
> -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> -      return is_nothrow_convertible (type1, type2);
> -
>      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
>        return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
>  
> @@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>  	return error_mark_node;
>        break;
>  
> +    case CPTK_IS_ABSTRACT:
>      case CPTK_IS_EMPTY:
>      case CPTK_IS_POLYMORPHIC:
> -    case CPTK_IS_ABSTRACT:
>      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
>        if (!check_trait_type (type1, /* kind = */ 3))
>  	return error_mark_node;
> @@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>  	return error_mark_node;
>        break;
>  
> -    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> -    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> +    case CPTK_IS_CONVERTIBLE:
>      case CPTK_IS_NOTHROW_ASSIGNABLE:
>      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> -    case CPTK_IS_CONVERTIBLE:
>      case CPTK_IS_NOTHROW_CONVERTIBLE:
> +    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> +    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
>      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
>      case CPTK_REF_CONVERTS_FROM_TEMPORARY:
>        if (!check_trait_type (type1)
> @@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>  
>      case CPTK_IS_CLASS:
>      case CPTK_IS_ENUM:
> -    case CPTK_IS_UNION:
>      case CPTK_IS_SAME:
> +    case CPTK_IS_UNION:
>        break;
>  
>      case CPTK_IS_LAYOUT_COMPATIBLE:
> @@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
>  
>    switch (kind)
>      {
> -    case CPTK_UNDERLYING_TYPE:
> -      return finish_underlying_type (type1);
> -
>      case CPTK_REMOVE_CV:
>        return cv_unqualified (type1);
>  
> -    case CPTK_REMOVE_REFERENCE:
> +    case CPTK_REMOVE_CVREF:
>        if (TYPE_REF_P (type1))
>  	type1 = TREE_TYPE (type1);
> -      return type1;
> +      return cv_unqualified (type1);
>  
> -    case CPTK_REMOVE_CVREF:
> +    case CPTK_REMOVE_REFERENCE:
>        if (TYPE_REF_P (type1))
>  	type1 = TREE_TYPE (type1);
> -      return cv_unqualified (type1);
> +      return type1;
>  
>      case CPTK_TYPE_PACK_ELEMENT:
>        return finish_type_pack_element (type1, type2, complain);
>  
> +    case CPTK_UNDERLYING_TYPE:
> +      return finish_underlying_type (type1);
> +
>  #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
>      case CPTK_##CODE:
>  #include "cp-trait.def"
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index f343e153e56..2223f08a628 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -8,9 +8,21 @@
>  #if !__has_builtin (__builtin_bit_cast)
>  # error "__has_builtin (__builtin_bit_cast) failed"
>  #endif
> +#if !__has_builtin (__builtin_is_constant_evaluated)
> +# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> +#endif
> +#if !__has_builtin (__builtin_is_corresponding_member)
> +# error "__has_builtin (__builtin_is_corresponding_member) failed"
> +#endif
> +#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> +# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> +#endif
>  #if !__has_builtin (__builtin_launder)
>  # error "__has_builtin (__builtin_launder) failed"
>  #endif
> +#if !__has_builtin (__builtin_source_location)
> +# error "__has_builtin (__builtin_source_location) failed"
> +#endif
>  #if !__has_builtin (__has_nothrow_assign)
>  # error "__has_builtin (__has_nothrow_assign) failed"
>  #endif
> @@ -44,12 +56,21 @@
>  #if !__has_builtin (__is_aggregate)
>  # error "__has_builtin (__is_aggregate) failed"
>  #endif
> +#if !__has_builtin (__is_assignable)
> +# error "__has_builtin (__is_assignable) failed"
> +#endif
>  #if !__has_builtin (__is_base_of)
>  # error "__has_builtin (__is_base_of) failed"
>  #endif
>  #if !__has_builtin (__is_class)
>  # error "__has_builtin (__is_class) failed"
>  #endif
> +#if !__has_builtin (__is_constructible)
> +# error "__has_builtin (__is_constructible) failed"
> +#endif
> +#if !__has_builtin (__is_convertible)
> +# error "__has_builtin (__is_convertible) failed"
> +#endif
>  #if !__has_builtin (__is_empty)
>  # error "__has_builtin (__is_empty) failed"
>  #endif
> @@ -65,6 +86,15 @@
>  #if !__has_builtin (__is_literal_type)
>  # error "__has_builtin (__is_literal_type) failed"
>  #endif
> +#if !__has_builtin (__is_nothrow_assignable)
> +# error "__has_builtin (__is_nothrow_assignable) failed"
> +#endif
> +#if !__has_builtin (__is_nothrow_constructible)
> +# error "__has_builtin (__is_nothrow_constructible) failed"
> +#endif
> +#if !__has_builtin (__is_nothrow_convertible)
> +# error "__has_builtin (__is_nothrow_convertible) failed"
> +#endif
>  #if !__has_builtin (__is_pointer_interconvertible_base_of)
>  # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
>  #endif
> @@ -98,51 +128,21 @@
>  #if !__has_builtin (__is_union)
>  # error "__has_builtin (__is_union) failed"
>  #endif
> -#if !__has_builtin (__underlying_type)
> -# error "__has_builtin (__underlying_type) failed"
> -#endif
> -#if !__has_builtin (__is_assignable)
> -# error "__has_builtin (__is_assignable) failed"
> -#endif
> -#if !__has_builtin (__is_constructible)
> -# error "__has_builtin (__is_constructible) failed"
> -#endif
> -#if !__has_builtin (__is_nothrow_assignable)
> -# error "__has_builtin (__is_nothrow_assignable) failed"
> -#endif
> -#if !__has_builtin (__is_nothrow_constructible)
> -# error "__has_builtin (__is_nothrow_constructible) failed"
> -#endif
>  #if !__has_builtin (__reference_constructs_from_temporary)
>  # error "__has_builtin (__reference_constructs_from_temporary) failed"
>  #endif
>  #if !__has_builtin (__reference_converts_from_temporary)
>  # error "__has_builtin (__reference_converts_from_temporary) failed"
>  #endif
> -#if !__has_builtin (__builtin_is_constant_evaluated)
> -# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> -#endif
> -#if !__has_builtin (__builtin_source_location)
> -# error "__has_builtin (__builtin_source_location) failed"
> -#endif
> -#if !__has_builtin (__builtin_is_corresponding_member)
> -# error "__has_builtin (__builtin_is_corresponding_member) failed"
> -#endif
> -#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> -# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> -#endif
> -#if !__has_builtin (__is_convertible)
> -# error "__has_builtin (__is_convertible) failed"
> -#endif
> -#if !__has_builtin (__is_nothrow_convertible)
> -# error "__has_builtin (__is_nothrow_convertible) failed"
> -#endif
>  #if !__has_builtin (__remove_cv)
>  # error "__has_builtin (__remove_cv) failed"
>  #endif
> +#if !__has_builtin (__remove_cvref)
> +# error "__has_builtin (__remove_cvref) failed"
> +#endif
>  #if !__has_builtin (__remove_reference)
>  # error "__has_builtin (__remove_reference) failed"
>  #endif
> -#if !__has_builtin (__remove_cvref)
> -# error "__has_builtin (__remove_cvref) failed"
> +#if !__has_builtin (__underlying_type)
> +# error "__has_builtin (__underlying_type) failed"
>  #endif
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance
  2023-10-16  0:10                 ` [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
@ 2023-10-16 16:36                   ` Patrick Palka
  2023-10-16 20:22                     ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 16:36 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Jonathan Wakely

On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch optimizes the performance of the is_pointer trait by dispatching to
> the new __is_pointer built-in trait.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
> 	built-in trait.
> 	* include/std/type_traits (is_pointer): Likewise. Optimize its
> 	implementation.
> 	(is_pointer_v): Likewise.
> 
> Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
>  libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
>  2 files changed, 44 insertions(+), 8 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
> index 4312f32a4e0..cd5ce45951f 100644
> --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>    //
>    // Pointer types
>    //
> +#if __has_builtin(__is_pointer)

Why not _GLIBCXX_USE_BUILTIN_TRAIT?  LGTM besides this.

> +  template<typename _Tp>
> +    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> +    {
> +      enum { __value = __is_pointer(_Tp) };
> +    };

Nice :D

> +#else
>    template<typename _Tp>
>      struct __is_pointer
>      {
> @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>        enum { __value = 1 };
>        typedef __true_type __type;
>      };
> +#endif
>  
>    //
>    // An arithmetic type is an integer type or a floating point type
> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> index 9c56d15c0b7..3acd843f2f2 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      : public true_type { };
>  #endif
>  
> -  template<typename>
> -    struct __is_pointer_helper
> +  /// is_pointer
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +  template<typename _Tp>
> +    struct is_pointer
> +    : public __bool_constant<__is_pointer(_Tp)>
> +    { };
> +#else
> +  template<typename _Tp>
> +    struct is_pointer
>      : public false_type { };
>  
>    template<typename _Tp>
> -    struct __is_pointer_helper<_Tp*>
> +    struct is_pointer<_Tp*>
>      : public true_type { };
>  
> -  /// is_pointer
>    template<typename _Tp>
> -    struct is_pointer
> -    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> -    { };
> +    struct is_pointer<_Tp* const>
> +    : public true_type { };
> +
> +  template<typename _Tp>
> +    struct is_pointer<_Tp* volatile>
> +    : public true_type { };
> +
> +  template<typename _Tp>
> +    struct is_pointer<_Tp* const volatile>
> +    : public true_type { };
> +#endif
>  
>    /// is_lvalue_reference
>    template<typename>
> @@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
>    inline constexpr bool is_array_v<_Tp[_Num]> = true;
>  #endif
>  
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> +#else
>  template <typename _Tp>
> -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> +  inline constexpr bool is_pointer_v = false;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp*> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> +#endif
> +
>  template <typename _Tp>
>    inline constexpr bool is_lvalue_reference_v = false;
>  template <typename _Tp>
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait
  2023-10-16  0:10                 ` [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
@ 2023-10-16 17:16                   ` Patrick Palka
  2023-10-16 20:25                     ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 17:16 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch implements built-in trait for std::is_arithmetic.
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-trait.def: Define __is_arithmetic.
> 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
> 	* semantics.cc (trait_expr_value): Likewise.
> 	(finish_trait_expr): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
> 	* g++.dg/ext/is_arithmetic.C: New test.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  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_arithmetic.C | 33 ++++++++++++++++++++++++
>  5 files changed, 44 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index c9d627fa782..3a7f968eae8 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_IS_AGGREGATE:
>        inform (loc, "  %qT is not an aggregate", t1);
>        break;
> +    case CPTK_IS_ARITHMETIC:
> +      inform (loc, "  %qT is not an arithmetic type", t1);
> +      break;
>      case CPTK_IS_ARRAY:
>        inform (loc, "  %qT is not an array", t1);
>        break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index c60724e869e..b2be7b7bbd7 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
>  DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
>  DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
>  DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
> +DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
>  DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
>  DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
>  DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 83ed674b9d4..deab0134509 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_AGGREGATE:
>        return CP_AGGREGATE_TYPE_P (type1);
>  
> +    case CPTK_IS_ARITHMETIC:
> +      return ARITHMETIC_TYPE_P (type1);
> +

For built-ins corresponding to is_arithmetic and other standard traits
defined in terms of it (e.g.  is_scalar, is_unsigned, is_signed,
is_fundamental) we need to make sure we preserve their behavior for
__int128, which IIUC is currently recognized as an integral type
(according to std::is_integral) only in GNU mode.

This'll probably be subtle to get right, so if you don't mind let's
split out the work for those built-in traits into a separate patch
series in order to ease review of the main patch series.

>      case CPTK_IS_ARRAY:
>        return type_code1 == ARRAY_TYPE;
>  
> @@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>  	return error_mark_node;
>        break;
>  
> +    case CPTK_IS_ARITHMETIC:
>      case CPTK_IS_ARRAY:
>      case CPTK_IS_BOUNDED_ARRAY:
>      case CPTK_IS_CLASS:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index efce04fd09d..4bc85f4babb 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -56,6 +56,9 @@
>  #if !__has_builtin (__is_aggregate)
>  # error "__has_builtin (__is_aggregate) failed"
>  #endif
> +#if !__has_builtin (__is_arithmetic)
> +# error "__has_builtin (__is_arithmetic) failed"
> +#endif
>  #if !__has_builtin (__is_array)
>  # error "__has_builtin (__is_array) failed"
>  #endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> new file mode 100644
> index 00000000000..fd35831f646
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> @@ -0,0 +1,33 @@
> +// { 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_arithmetic, void, false);
> +
> +SA_TEST_CATEGORY(__is_arithmetic, char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
> +SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
> +SA_TEST_CATEGORY(__is_arithmetic, short, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
> +SA_TEST_CATEGORY(__is_arithmetic, int, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
> +SA_TEST_CATEGORY(__is_arithmetic, long, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
> +SA_TEST_CATEGORY(__is_arithmetic, long long, true);
> +SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
> +SA_TEST_CATEGORY(__is_arithmetic, float, true);
> +SA_TEST_CATEGORY(__is_arithmetic, double, true);
> +SA_TEST_CATEGORY(__is_arithmetic, long double, true);
> +
> +// Sanity check.
> +SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 26/40] libstdc++: Optimize is_object trait performance
  2023-10-16  0:10                 ` [PATCH v20 26/40] libstdc++: Optimize is_object " Ken Matsui
@ 2023-10-16 18:04                   ` Patrick Palka
  2023-10-16 20:26                     ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 18:04 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Sun, 15 Oct 2023, Ken Matsui wrote:

> This patch optimizes the performance of the is_object trait by dispatching to
> the new __is_function and __is_reference built-in traits.
> 
> libstdc++-v3/ChangeLog:
> 	* include/std/type_traits (is_object): Use __is_function and
> 	__is_reference built-in traits.
> 	(is_object_v): Likewise.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> index bd57488824b..674d398c075 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      { };
>  
>    /// is_object
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> +  template<typename _Tp>
> +    struct is_object
> +    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
> +                             || is_void<_Tp>::value)>
> +    { };

Since is_object is one of the more commonly used traits, we should
probably just define a built-in for it.  (Either way we'd have to
repeat the logic twice, either once in the frontend and once in
the library, or twice in the library (is_object and is_object_v),
so might as well do the more efficient approach).

> +#else
>    template<typename _Tp>
>      struct is_object
>      : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
>                            is_void<_Tp>>>::type
>      { };
> +#endif
>  
>    template<typename>
>      struct is_member_pointer;
> @@ -3305,8 +3314,17 @@ template <typename _Tp>
>    inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
>  template <typename _Tp>
>    inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
> +
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> +template <typename _Tp>
> +  inline constexpr bool is_object_v
> +    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
> +#else
>  template <typename _Tp>
>    inline constexpr bool is_object_v = is_object<_Tp>::value;
> +#endif
> +
>  template <typename _Tp>
>    inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
>  template <typename _Tp>
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node
  2023-10-16 14:55                   ` Patrick Palka
@ 2023-10-16 19:57                     ` Ken Matsui
  2023-10-16 21:06                       ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 19:57 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 7:55 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > once in a C++ translation unit, this patch removes all RID values for built-in
> > traits and uses the identifier node to look up the specific trait.  Rather
> > than holding traits as keywords, we set all trait identifiers as cik_trait,
> > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > identifier so that we accept the use of non-function-like built-in trait
> > identifiers.
>
> Thanks, this looks great!  Some review comments below.
>

Thank you so much for your review :)

> >
> > gcc/c-family/ChangeLog:
> >
> >       * c-common.cc (c_common_reswords): Remove all mappings of
> >       built-in traits.
> >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> >
> > gcc/cp/ChangeLog:
> >
> >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> >       cases for built-in traits.  Check for built-in traits via
> >       the new cik_trait kind.
> >       * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> >       addr_space_t.
> >       (struct cp_trait): New struct to hold trait information.
> >       (cp_traits): New array to hold a mapping to all traits.
> >       (cik_reserved_for_udlit): Rename to ...
> >       (cik_trait): ... this.
> >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> >       built-in trait identifiers.
>
> We should mention setting IDENTIFIER_CP_INDEX as well.
>

Thank you!

> >       (cxx_init): Call init_cp_traits function.
> >       * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> >       (cp_lexer_lookup_trait): New function to look up a
> >       built-in trait by IDENTIFIER_CP_INDEX.
> >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> >       expression-yielding built-in trait.
> >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> >       built-in trait.
> >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> >       for built-in traits.
> >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> >       type-yielding built-in traits.
> >       (cp_parser_primary_expression): Remove all RID value cases for
> >       built-in traits.  Handle expression-yielding built-in traits.
> >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> >       (cp_parser_simple_type_specifier): Remove all RID value cases
> >       for built-in traits.  Handle type-yielding built-in traits.
> >
> > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/c-family/c-common.cc  |   7 --
> >  gcc/c-family/c-common.h   |   5 --
> >  gcc/cp/cp-objcp-common.cc |   8 +--
> >  gcc/cp/cp-tree.h          |  31 ++++++---
> >  gcc/cp/lex.cc             |  21 ++++++
> >  gcc/cp/parser.cc          | 141 ++++++++++++++++++++++++--------------
> >  6 files changed, 139 insertions(+), 74 deletions(-)
> >
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index f044db5b797..21fd333ef57 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
> > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> >    { "while",         RID_WHILE,      0 },
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -  /* An alias for __is_same.  */
> > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > -
> >    /* C++ transactional memory.  */
> >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 1fdba7ef3ea..051a442e0f4 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -168,11 +168,6 @@ enum rid
> >    RID_BUILTIN_LAUNDER,
> >    RID_BUILTIN_BIT_CAST,
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  RID_##CODE,
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -
> >    /* C++11 */
> >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> >
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 93b027b80ce..b1adacfec07 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> >       }
> >      }
> >
> > +  /* Check for built-in traits.  */
> > +  if (IDENTIFIER_TRAIT_P (id))
> > +    return true;
> > +
> >    /* Also detect common reserved C++ words that aren't strictly built-in
> >       functions.  */
> >    switch (C_RID_CODE (id))
> > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> >      case RID_BUILTIN_ASSOC_BARRIER:
> >      case RID_BUILTIN_BIT_CAST:
> >      case RID_OFFSETOF:
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> >        return true;
> >      default:
> >        break;
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 6e34952da99..583abb2e79a 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> >    cik_simple_op = 4, /* Non-assignment operator name.  */
> >    cik_assign_op = 5, /* An assignment operator name.  */
> >    cik_conv_op = 6,   /* Conversion operator name.  */
> > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > +  cik_trait = 7,     /* Built-in trait name.  */
> >    cik_max
> >  };
> >
> > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> >      & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is for any operator name (including
> > -   conversions).  Value 4, 5, 6 or 7.  */
> > +   conversions).  Value 4, 5, or 6.  */
> >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> >
> >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> >     & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is the name of a type-conversion
> > -   operator.  Value 7.  */
> > +   operator.  Value 6.  */
> >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> >
> > +/* True if this identifier is the name of a built-in trait.  */
> > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > +
> >  /* True if this identifier is a new or delete operator.  */
> >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > @@ -1375,16 +1381,25 @@ struct GTY (()) tree_argument_pack_select {
> >    int index;
> >  };
> >
> > -/* The different kinds of traits that we encounter.  */
> > -
> > -enum cp_trait_kind
> > -{
> > +/* The different kinds of traits that we encounter.  The size is limited to
> > +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> > +enum cp_trait_kind : addr_space_t {
> >  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> >    CPTK_##CODE,
> >  #include "cp-trait.def"
> >  #undef DEFTRAIT
> >  };
> >
> > +/* The trait type.  */
> > +struct cp_trait {
> > +  short arity;
> > +  cp_trait_kind kind;
> > +  bool type;
>
> Could we also store the const char* name of each trait here, so that ...
>
> > +};
> > +
> > +/* The trait table.  */
> > +extern const struct cp_trait cp_traits[];
> > +
> >  /* The types that we are processing.  */
> >  #define TRAIT_EXPR_TYPE1(NODE) \
> >    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > index 64bcfb18196..16a82a12a02 100644
> > --- a/gcc/cp/lex.cc
> > +++ b/gcc/cp/lex.cc
> > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "langhooks.h"
> >
> >  static int interface_strcmp (const char *);
> > +static void init_cp_traits (void);
> >  static void init_cp_pragma (void);
> >
> >  static tree parse_strconst_pragma (const char *, int);
> > @@ -283,6 +284,25 @@ init_reswords (void)
> >      }
> >  }
> >
> > +/* Initialize the C++ traits.  */
> > +static void
> > +init_cp_traits (void)
> > +{
> > +  tree id;
> > +
> > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > +  id = get_identifier (NAME); \
> > +  IDENTIFIER_CP_INDEX (id) = CPTK_##CODE; \
> > +  set_identifier_kind (id, cik_trait);
> > +#include "cp/cp-trait.def"
> > +#undef DEFTRAIT
>
> ... we could replace this straight-line code with a loop over cp_traits?
> It'd make cp_traits bigger but init_cp_traits should get much smaller,
> which should be a net win in terms of binary size.
>

I see. Since we know the number of iterations would be up to 255 and
the inner statements are only 3 and pretty simple/small, I think it is
likely that we will benefit from loop unrolling. But do we want to
prioritize the binary size over the possible performance improvements?

> > +
> > +  /* An alias for __is_same.  */
> > +  id = get_identifier ("__is_same_as");
> > +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> > +  set_identifier_kind (id, cik_trait);
> > +}
> > +
> >  static void
> >  init_cp_pragma (void)
> >  {
> > @@ -324,6 +344,7 @@ cxx_init (void)
> >    input_location = BUILTINS_LOCATION;
> >
> >    init_reswords ();
> > +  init_cp_traits ();
> >    init_tree ();
> >    init_cp_semantics ();
> >    init_operators ();
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index f3abae716fe..eba5272be03 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> >  static void cp_lexer_stop_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > +static const cp_trait *cp_lexer_lookup_trait
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_expr
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_type
> > +  (const cp_token *);
> >
> >  static cp_token_cache *cp_token_cache_new
> >    (cp_token *, cp_token *);
> > @@ -279,6 +285,19 @@ static FILE *cp_lexer_debug_stream;
> >     sizeof, typeof, or alignof.  */
> >  int cp_unevaluated_operand;
> >
> > +/* The trait table, declared in cp-tree.h.  */
> > +const cp_trait cp_traits[] =
> > +{
> > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > +  { ARITY, CPTK_##CODE, (TCC == tcc_type) },
> > +#include "cp-trait.def"
> > +#undef DEFTRAIT
> > +};
> > +/* The trait table cannot have more than 255 (addr_space_t) entries since
> > +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> > +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> > +              "cp_traits array cannot have more than 255 entries");
> > +
> >  /* Dump up to NUM tokens in BUFFER to FILE starting with token
> >     START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
> >     first token in BUFFER.  If NUM is 0, dump all the tokens.  If
> > @@ -1167,12 +1186,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      case RID_CONSTEVAL:
> >        return true;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      return true;
> > -
> >      default:
> >        if (keyword >= RID_FIRST_INT_N
> >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > @@ -1182,6 +1195,48 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      }
> >  }
> >
> > +/* Look ups the corresponding built-in trait if a given token is
> > +   a built-in trait.  Otherwise, returns nullptr.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait (const cp_token *token)
> > +{
> > +  tree id = token->u.value;
> > +
> > +  if (token->type == CPP_NAME
> > +      && TREE_CODE (id) == IDENTIFIER_NODE
>
> The value of a CPP_NAME token is always an IDENTIFIER_NODE, so this
> check should be redundant.  Also we should access the u.value union member
> only after the CPP_NAME check, since for some other token kinds u.value
> isn't the active member (and reading from it would be undefined behavior
> strictly speaking).
>

Thank you!

> > +      && IDENTIFIER_TRAIT_P (id))
> > +    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
> > +
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is an expression-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && !trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is a type-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_type (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> >  /* Return true if the next token is a keyword for a decl-specifier.  */
> >
> >  static bool
> > @@ -1190,6 +1245,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> >    cp_token *token;
> >
> >    token = cp_lexer_peek_token (lexer);
> > +  if (cp_lexer_lookup_trait_type (token))
> > +    return true;
> >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> >  }
> >
> > @@ -2854,7 +2911,7 @@ static void cp_parser_late_parsing_default_args
> >  static tree cp_parser_sizeof_operand
> >    (cp_parser *, enum rid);
> >  static cp_expr cp_parser_trait
> > -  (cp_parser *, enum rid);
> > +  (cp_parser *, const cp_trait *);
> >  static bool cp_parser_declares_only_class_p
> >    (cp_parser *);
> >  static void cp_parser_set_storage_class
> > @@ -6021,12 +6078,6 @@ cp_parser_primary_expression (cp_parser *parser,
> >       case RID_OFFSETOF:
> >         return cp_parser_builtin_offsetof (parser);
> >
> > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > -     case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_EXPR
> > -       return cp_parser_trait (parser, token->keyword);
> > -
> >       // C++ concepts
> >       case RID_REQUIRES:
> >         return cp_parser_requires_expression (parser);
> > @@ -6065,6 +6116,12 @@ cp_parser_primary_expression (cp_parser *parser,
> >        `::' as the beginning of a qualified-id, or the "operator"
> >        keyword.  */
> >      case CPP_NAME:
> > +      {
> > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > +     if (trait)
>
> A tiny nit, but we could remove the extra block scope here by doing
> 'if (const cp_trait* trait = ...)' instead.
>

Thank you!

> > +       return cp_parser_trait (parser, trait);
> > +      }
> > +      /* FALLTHRU */
> >      case CPP_SCOPE:
> >      case CPP_TEMPLATE_ID:
> >      case CPP_NESTED_NAME_SPECIFIER:
> > @@ -11033,28 +11090,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> >  /* Parse a builtin trait expression or type.  */
> >
> >  static cp_expr
> > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> >  {
> > -  cp_trait_kind kind;
> >    tree type1, type2 = NULL_TREE;
> > -  bool binary = false;
> > -  bool variadic = false;
> > -  bool type = false;
> > -
> > -  switch (keyword)
> > -    {
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:                  \
> > -      kind = CPTK_##CODE;             \
> > -      binary = (ARITY == 2);          \
> > -      variadic = (ARITY == -1);               \
> > -      type = (TCC == tcc_type);               \
> > -      break;
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > -    default:
> > -      gcc_unreachable ();
> > -    }
> > +  const bool binary = (trait->arity == 2);
> > +  const bool variadic = (trait->arity == -1);
>
> Could we continue defining the local variables 'kind' and 'type' here so
> that we don't have to adjust their uses in the rest of the function?
> That should yield a smaller diff for this function.
>

Yes, I will update this patch. Thank you!

> >
> >    /* Get location of initial token.  */
> >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > @@ -11063,12 +11103,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    cp_lexer_consume_token (parser->lexer);
> >
> >    matching_parens parens;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> >    else
> >      parens.require_open (parser);
> >
> > -  if (kind == CPTK_IS_DEDUCIBLE)
> > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> >      {
> >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> >        type1 = cp_parser_id_expression (parser,
> > @@ -11079,7 +11119,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >                                      /*optional_p=*/false);
> >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> >      }
> > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* __type_pack_element takes an expression as its first argument and uses
> >         template-id syntax instead of function call syntax (for consistency
> >         with Clang).  We special case these properties of __type_pack_element
> > @@ -11094,7 +11134,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >    if (type1 == error_mark_node)
> >      return error_mark_node;
> >
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      {
> >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > @@ -11144,7 +11184,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >      }
> >
> >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> >      /* cp_parser_enclosed_template_argument_list above already took care
> >         of parsing the closing '>'.  */;
> >    else
> > @@ -11158,17 +11198,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >
> >    /* Complete the trait expression, which may mean either processing
> >       the trait expr now or saving it for template instantiation.  */
> > -  switch (kind)
> > +  switch (trait->kind)
> >      {
> >      case CPTK_BASES:
> >        return cp_expr (finish_bases (type1, false), trait_loc);
> >      case CPTK_DIRECT_BASES:
> >        return cp_expr (finish_bases (type1, true), trait_loc);
> >      default:
> > -      if (type)
> > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > +      if (trait->type)
> > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> >        else
> > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> >      }
> >  }
> >
> > @@ -20081,20 +20121,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> >
> >        return type;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      type = cp_parser_trait (parser, token->keyword);
> > +    default:
> > +      break;
> > +    }
> > +
> > +  /* If token is a type-yielding built-in traits, parse it.  */
> > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > +  if (trait)
> > +    {
> > +      type = cp_parser_trait (parser, trait);
> >        if (decl_specs)
> >       cp_parser_set_decl_spec_type (decl_specs, type,
> >                                     token,
> >                                     /*type_definition_p=*/false);
> >
> >        return type;
> > -
> > -    default:
> > -      break;
> >      }
> >
> >    /* If token is an already-parsed decltype not followed by ::,
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically
  2023-10-16 15:16                   ` Patrick Palka
@ 2023-10-16 20:11                     ` Ken Matsui
  2023-10-16 21:12                       ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 20:11 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 8:17 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > This patch sorts built-in traits alphabetically for better code
> > readability.
>
> Hmm, I'm not sure if we still want/need this change with this current
> approach.  IIUC gperf would sort the trait names when generating the
> hash table code, and so we wanted a more consistent mapping from the
> cp-trait.def file to the generated code.  But with this current
> non-gperf approach I'm inclined to leave the existing ordering alone
> for sake of simplicity, and I kind of like that in cp-trait.def we
> currently group all expression-yielding traits together and all
> type-yielding traits together; that seems like a more natural layout
> than plain alphabetical sorting.
>

I see. But this patch is crucial for me to keep all my existing
patches almost conflict-free against rebase, including drop, add, and
edit like you suggested to split integral-related patches. Without
this patch and alphabetical order, I will need to put a new trait in a
random place not close to surrounding commits, as Git relates close
lines when it finds conflicts. When I merged all my patches into one
patch series, I needed to fix conflicts for all my patches almost
every time I rebased. Both thinking of the random place and fixing the
conflicts of all patches would definitely not be desirable. Would you
think we should drop this patch?

> >
> > gcc/cp/ChangeLog:
> >
> >       * constraint.cc (diagnose_trait_expr): Sort built-in traits
> >       alphabetically.
> >       * cp-trait.def: Likewise.
> >       * semantics.cc (trait_expr_value): Likewise.
> >       (finish_trait_expr): Likewise.
> >       (finish_trait_type): Likewise.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> >
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/cp/constraint.cc                     | 68 ++++++++---------
> >  gcc/cp/cp-trait.def                      | 10 +--
> >  gcc/cp/semantics.cc                      | 94 ++++++++++++------------
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
> >  4 files changed, 121 insertions(+), 121 deletions(-)
> >
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index c9e4e7043cd..722fc334e6f 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
> >      case CPTK_HAS_TRIVIAL_DESTRUCTOR:
> >        inform (loc, "  %qT is not trivially destructible", t1);
> >        break;
> > +    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > +      inform (loc, "  %qT does not have unique object representations", t1);
> > +      break;
> >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> >        inform (loc, "  %qT does not have a virtual destructor", t1);
> >        break;
> >      case CPTK_IS_ABSTRACT:
> >        inform (loc, "  %qT is not an abstract class", t1);
> >        break;
> > +    case CPTK_IS_AGGREGATE:
> > +      inform (loc, "  %qT is not an aggregate", t1);
> > +      break;
> > +    case CPTK_IS_ASSIGNABLE:
> > +      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > +      break;
> >      case CPTK_IS_BASE_OF:
> >        inform (loc, "  %qT is not a base of %qT", t1, t2);
> >        break;
> >      case CPTK_IS_CLASS:
> >        inform (loc, "  %qT is not a class", t1);
> >        break;
> > +    case CPTK_IS_CONSTRUCTIBLE:
> > +      if (!t2)
> > +    inform (loc, "  %qT is not default constructible", t1);
> > +      else
> > +    inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > +      break;
> > +    case CPTK_IS_CONVERTIBLE:
> > +      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > +      break;
> >      case CPTK_IS_EMPTY:
> >        inform (loc, "  %qT is not an empty class", t1);
> >        break;
> > @@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
> >      case CPTK_IS_LITERAL_TYPE:
> >        inform (loc, "  %qT is not a literal type", t1);
> >        break;
> > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > +      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > +      break;
> > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > +      if (!t2)
> > +     inform (loc, "  %qT is not nothrow default constructible", t1);
> > +      else
> > +     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > +      break;
> > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > +       inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > +      break;
> >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> >        inform (loc, "  %qT is not pointer-interconvertible base of %qT",
> >             t1, t2);
> > @@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
> >      case CPTK_IS_TRIVIAL:
> >        inform (loc, "  %qT is not a trivial type", t1);
> >        break;
> > -    case CPTK_IS_UNION:
> > -      inform (loc, "  %qT is not a union", t1);
> > -      break;
> > -    case CPTK_IS_AGGREGATE:
> > -      inform (loc, "  %qT is not an aggregate", t1);
> > -      break;
> > -    case CPTK_IS_TRIVIALLY_COPYABLE:
> > -      inform (loc, "  %qT is not trivially copyable", t1);
> > -      break;
> > -    case CPTK_IS_ASSIGNABLE:
> > -      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > -      break;
> >      case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> >        inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
> >        break;
> > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > -      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > -      break;
> > -    case CPTK_IS_CONSTRUCTIBLE:
> > -      if (!t2)
> > -     inform (loc, "  %qT is not default constructible", t1);
> > -      else
> > -     inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > -      break;
> >      case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> >        if (!t2)
> >       inform (loc, "  %qT is not trivially default constructible", t1);
> >        else
> >       inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
> >        break;
> > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > -      if (!t2)
> > -     inform (loc, "  %qT is not nothrow default constructible", t1);
> > -      else
> > -     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > -      break;
> > -    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > -      inform (loc, "  %qT does not have unique object representations", t1);
> > -      break;
> > -    case CPTK_IS_CONVERTIBLE:
> > -      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > +    case CPTK_IS_TRIVIALLY_COPYABLE:
> > +      inform (loc, "  %qT is not trivially copyable", t1);
> >        break;
> > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > -     inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > +    case CPTK_IS_UNION:
> > +      inform (loc, "  %qT is not a union", t1);
> >        break;
> >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> >        inform (loc, "  %qT is not a reference that binds to a temporary "
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 8b7fece0cc8..0e48e64b8dd 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
> >  DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
> > -DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> > -
> >  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> > -DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> >  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> > -DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> >  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> > +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
> > +
> > +/* FIXME Added space to avoid direct usage in GCC 13.  */
> > +DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> >
> >  /* These traits yield a type pack, not a type, and are represented by
> >     cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 80ef1364e33..782aa515da0 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >                     && classtype_has_nothrow_assign_or_copy_p (type1,
> >                                                                true))));
> >
> > -    case CPTK_HAS_TRIVIAL_ASSIGN:
> > -      /* ??? The standard seems to be missing the "or array of such a class
> > -      type" wording for this trait.  */
> > -      type1 = strip_array_types (type1);
> > -      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > -           && (trivial_type_p (type1)
> > -                 || (CLASS_TYPE_P (type1)
> > -                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > -
> >      case CPTK_HAS_NOTHROW_CONSTRUCTOR:
> >        type1 = strip_array_types (type1);
> >        return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
> > @@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >                 && maybe_instantiate_noexcept (t)
> >                 && TYPE_NOTHROW_P (TREE_TYPE (t))));
> >
> > -    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > -      type1 = strip_array_types (type1);
> > -      return (trivial_type_p (type1)
> > -           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > -
> >      case CPTK_HAS_NOTHROW_COPY:
> >        type1 = strip_array_types (type1);
> >        return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
> >             || (CLASS_TYPE_P (type1)
> >                 && classtype_has_nothrow_assign_or_copy_p (type1, false)));
> >
> > +    case CPTK_HAS_TRIVIAL_ASSIGN:
> > +      /* ??? The standard seems to be missing the "or array of such a class
> > +      type" wording for this trait.  */
> > +      type1 = strip_array_types (type1);
> > +      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > +           && (trivial_type_p (type1)
> > +                 || (CLASS_TYPE_P (type1)
> > +                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > +
> > +    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > +      type1 = strip_array_types (type1);
> > +      return (trivial_type_p (type1)
> > +           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > +
> >      case CPTK_HAS_TRIVIAL_COPY:
> >        /* ??? The standard seems to be missing the "or array of such a class
> >        type" wording for this trait.  */
> > @@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >             || (CLASS_TYPE_P (type1)
> >                 && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
> >
> > -    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > -      return type_has_virtual_destructor (type1);
> > -
> >      case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> >        return type_has_unique_obj_representations (type1);
> >
> > +    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > +      return type_has_virtual_destructor (type1);
> > +
> >      case CPTK_IS_ABSTRACT:
> >        return ABSTRACT_CLASS_TYPE_P (type1);
> >
> >      case CPTK_IS_AGGREGATE:
> >        return CP_AGGREGATE_TYPE_P (type1);
> >
> > +    case CPTK_IS_ASSIGNABLE:
> > +      return is_xible (MODIFY_EXPR, type1, type2);
> > +
> >      case CPTK_IS_BASE_OF:
> >        return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
> >             && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
> > @@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >      case CPTK_IS_CLASS:
> >        return NON_UNION_CLASS_TYPE_P (type1);
> >
> > +    case CPTK_IS_CONSTRUCTIBLE:
> > +      return is_xible (INIT_EXPR, type1, type2);
> > +
> > +    case CPTK_IS_CONVERTIBLE:
> > +      return is_convertible (type1, type2);
> > +
> >      case CPTK_IS_EMPTY:
> >        return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
> >
> > @@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >      case CPTK_IS_LITERAL_TYPE:
> >        return literal_type_p (type1);
> >
> > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > +      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > +
> > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > +      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > +
> > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > +      return is_nothrow_convertible (type1, type2);
> > +
> >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> >        return pointer_interconvertible_base_of_p (type1, type2);
> >
> > @@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >      case CPTK_IS_UNION:
> >        return type_code1 == UNION_TYPE;
> >
> > -    case CPTK_IS_ASSIGNABLE:
> > -      return is_xible (MODIFY_EXPR, type1, type2);
> > -
> > -    case CPTK_IS_CONSTRUCTIBLE:
> > -      return is_xible (INIT_EXPR, type1, type2);
> > -
> > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > -      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > -
> > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > -      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > -
> > -    case CPTK_IS_CONVERTIBLE:
> > -      return is_convertible (type1, type2);
> > -
> > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > -      return is_nothrow_convertible (type1, type2);
> > -
> >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> >        return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
> >
> > @@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> >       return error_mark_node;
> >        break;
> >
> > +    case CPTK_IS_ABSTRACT:
> >      case CPTK_IS_EMPTY:
> >      case CPTK_IS_POLYMORPHIC:
> > -    case CPTK_IS_ABSTRACT:
> >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> >        if (!check_trait_type (type1, /* kind = */ 3))
> >       return error_mark_node;
> > @@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> >       return error_mark_node;
> >        break;
> >
> > -    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > -    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > +    case CPTK_IS_CONVERTIBLE:
> >      case CPTK_IS_NOTHROW_ASSIGNABLE:
> >      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > -    case CPTK_IS_CONVERTIBLE:
> >      case CPTK_IS_NOTHROW_CONVERTIBLE:
> > +    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > +    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> >      case CPTK_REF_CONVERTS_FROM_TEMPORARY:
> >        if (!check_trait_type (type1)
> > @@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> >
> >      case CPTK_IS_CLASS:
> >      case CPTK_IS_ENUM:
> > -    case CPTK_IS_UNION:
> >      case CPTK_IS_SAME:
> > +    case CPTK_IS_UNION:
> >        break;
> >
> >      case CPTK_IS_LAYOUT_COMPATIBLE:
> > @@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
> >
> >    switch (kind)
> >      {
> > -    case CPTK_UNDERLYING_TYPE:
> > -      return finish_underlying_type (type1);
> > -
> >      case CPTK_REMOVE_CV:
> >        return cv_unqualified (type1);
> >
> > -    case CPTK_REMOVE_REFERENCE:
> > +    case CPTK_REMOVE_CVREF:
> >        if (TYPE_REF_P (type1))
> >       type1 = TREE_TYPE (type1);
> > -      return type1;
> > +      return cv_unqualified (type1);
> >
> > -    case CPTK_REMOVE_CVREF:
> > +    case CPTK_REMOVE_REFERENCE:
> >        if (TYPE_REF_P (type1))
> >       type1 = TREE_TYPE (type1);
> > -      return cv_unqualified (type1);
> > +      return type1;
> >
> >      case CPTK_TYPE_PACK_ELEMENT:
> >        return finish_type_pack_element (type1, type2, complain);
> >
> > +    case CPTK_UNDERLYING_TYPE:
> > +      return finish_underlying_type (type1);
> > +
> >  #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> >      case CPTK_##CODE:
> >  #include "cp-trait.def"
> > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > index f343e153e56..2223f08a628 100644
> > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > @@ -8,9 +8,21 @@
> >  #if !__has_builtin (__builtin_bit_cast)
> >  # error "__has_builtin (__builtin_bit_cast) failed"
> >  #endif
> > +#if !__has_builtin (__builtin_is_constant_evaluated)
> > +# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > +#endif
> > +#if !__has_builtin (__builtin_is_corresponding_member)
> > +# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > +#endif
> > +#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > +# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > +#endif
> >  #if !__has_builtin (__builtin_launder)
> >  # error "__has_builtin (__builtin_launder) failed"
> >  #endif
> > +#if !__has_builtin (__builtin_source_location)
> > +# error "__has_builtin (__builtin_source_location) failed"
> > +#endif
> >  #if !__has_builtin (__has_nothrow_assign)
> >  # error "__has_builtin (__has_nothrow_assign) failed"
> >  #endif
> > @@ -44,12 +56,21 @@
> >  #if !__has_builtin (__is_aggregate)
> >  # error "__has_builtin (__is_aggregate) failed"
> >  #endif
> > +#if !__has_builtin (__is_assignable)
> > +# error "__has_builtin (__is_assignable) failed"
> > +#endif
> >  #if !__has_builtin (__is_base_of)
> >  # error "__has_builtin (__is_base_of) failed"
> >  #endif
> >  #if !__has_builtin (__is_class)
> >  # error "__has_builtin (__is_class) failed"
> >  #endif
> > +#if !__has_builtin (__is_constructible)
> > +# error "__has_builtin (__is_constructible) failed"
> > +#endif
> > +#if !__has_builtin (__is_convertible)
> > +# error "__has_builtin (__is_convertible) failed"
> > +#endif
> >  #if !__has_builtin (__is_empty)
> >  # error "__has_builtin (__is_empty) failed"
> >  #endif
> > @@ -65,6 +86,15 @@
> >  #if !__has_builtin (__is_literal_type)
> >  # error "__has_builtin (__is_literal_type) failed"
> >  #endif
> > +#if !__has_builtin (__is_nothrow_assignable)
> > +# error "__has_builtin (__is_nothrow_assignable) failed"
> > +#endif
> > +#if !__has_builtin (__is_nothrow_constructible)
> > +# error "__has_builtin (__is_nothrow_constructible) failed"
> > +#endif
> > +#if !__has_builtin (__is_nothrow_convertible)
> > +# error "__has_builtin (__is_nothrow_convertible) failed"
> > +#endif
> >  #if !__has_builtin (__is_pointer_interconvertible_base_of)
> >  # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
> >  #endif
> > @@ -98,51 +128,21 @@
> >  #if !__has_builtin (__is_union)
> >  # error "__has_builtin (__is_union) failed"
> >  #endif
> > -#if !__has_builtin (__underlying_type)
> > -# error "__has_builtin (__underlying_type) failed"
> > -#endif
> > -#if !__has_builtin (__is_assignable)
> > -# error "__has_builtin (__is_assignable) failed"
> > -#endif
> > -#if !__has_builtin (__is_constructible)
> > -# error "__has_builtin (__is_constructible) failed"
> > -#endif
> > -#if !__has_builtin (__is_nothrow_assignable)
> > -# error "__has_builtin (__is_nothrow_assignable) failed"
> > -#endif
> > -#if !__has_builtin (__is_nothrow_constructible)
> > -# error "__has_builtin (__is_nothrow_constructible) failed"
> > -#endif
> >  #if !__has_builtin (__reference_constructs_from_temporary)
> >  # error "__has_builtin (__reference_constructs_from_temporary) failed"
> >  #endif
> >  #if !__has_builtin (__reference_converts_from_temporary)
> >  # error "__has_builtin (__reference_converts_from_temporary) failed"
> >  #endif
> > -#if !__has_builtin (__builtin_is_constant_evaluated)
> > -# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > -#endif
> > -#if !__has_builtin (__builtin_source_location)
> > -# error "__has_builtin (__builtin_source_location) failed"
> > -#endif
> > -#if !__has_builtin (__builtin_is_corresponding_member)
> > -# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > -#endif
> > -#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > -# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > -#endif
> > -#if !__has_builtin (__is_convertible)
> > -# error "__has_builtin (__is_convertible) failed"
> > -#endif
> > -#if !__has_builtin (__is_nothrow_convertible)
> > -# error "__has_builtin (__is_nothrow_convertible) failed"
> > -#endif
> >  #if !__has_builtin (__remove_cv)
> >  # error "__has_builtin (__remove_cv) failed"
> >  #endif
> > +#if !__has_builtin (__remove_cvref)
> > +# error "__has_builtin (__remove_cvref) failed"
> > +#endif
> >  #if !__has_builtin (__remove_reference)
> >  # error "__has_builtin (__remove_reference) failed"
> >  #endif
> > -#if !__has_builtin (__remove_cvref)
> > -# error "__has_builtin (__remove_cvref) failed"
> > +#if !__has_builtin (__underlying_type)
> > +# error "__has_builtin (__underlying_type) failed"
> >  #endif
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance
  2023-10-16 16:36                   ` Patrick Palka
@ 2023-10-16 20:22                     ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 20:22 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++, Jonathan Wakely

On Mon, Oct 16, 2023 at 9:36 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > This patch optimizes the performance of the is_pointer trait by dispatching to
> > the new __is_pointer built-in trait.
> >
> > libstdc++-v3/ChangeLog:
> >
> >       * include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
> >       built-in trait.
> >       * include/std/type_traits (is_pointer): Likewise. Optimize its
> >       implementation.
> >       (is_pointer_v): Likewise.
> >
> > Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
> >  libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
> >  2 files changed, 44 insertions(+), 8 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
> > index 4312f32a4e0..cd5ce45951f 100644
> > --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> > +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> > @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >    //
> >    // Pointer types
> >    //
> > +#if __has_builtin(__is_pointer)
>
> Why not _GLIBCXX_USE_BUILTIN_TRAIT?  LGTM besides this.
>

Oops, thank you for pointing this out :)

> > +  template<typename _Tp>
> > +    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> > +    {
> > +      enum { __value = __is_pointer(_Tp) };
> > +    };
>
> Nice :D
>

Yeees! But I thought this might be very confusing for someone who does
not know the new built-in behavior.

> > +#else
> >    template<typename _Tp>
> >      struct __is_pointer
> >      {
> > @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >        enum { __value = 1 };
> >        typedef __true_type __type;
> >      };
> > +#endif
> >
> >    //
> >    // An arithmetic type is an integer type or a floating point type
> > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> > index 9c56d15c0b7..3acd843f2f2 100644
> > --- a/libstdc++-v3/include/std/type_traits
> > +++ b/libstdc++-v3/include/std/type_traits
> > @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >      : public true_type { };
> >  #endif
> >
> > -  template<typename>
> > -    struct __is_pointer_helper
> > +  /// is_pointer
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +  template<typename _Tp>
> > +    struct is_pointer
> > +    : public __bool_constant<__is_pointer(_Tp)>
> > +    { };
> > +#else
> > +  template<typename _Tp>
> > +    struct is_pointer
> >      : public false_type { };
> >
> >    template<typename _Tp>
> > -    struct __is_pointer_helper<_Tp*>
> > +    struct is_pointer<_Tp*>
> >      : public true_type { };
> >
> > -  /// is_pointer
> >    template<typename _Tp>
> > -    struct is_pointer
> > -    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> > -    { };
> > +    struct is_pointer<_Tp* const>
> > +    : public true_type { };
> > +
> > +  template<typename _Tp>
> > +    struct is_pointer<_Tp* volatile>
> > +    : public true_type { };
> > +
> > +  template<typename _Tp>
> > +    struct is_pointer<_Tp* const volatile>
> > +    : public true_type { };
> > +#endif
> >
> >    /// is_lvalue_reference
> >    template<typename>
> > @@ -3254,8 +3268,22 @@ template <typename _Tp, size_t _Num>
> >    inline constexpr bool is_array_v<_Tp[_Num]> = true;
> >  #endif
> >
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> > +#else
> >  template <typename _Tp>
> > -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> > +  inline constexpr bool is_pointer_v = false;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp*> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> > +#endif
> > +
> >  template <typename _Tp>
> >    inline constexpr bool is_lvalue_reference_v = false;
> >  template <typename _Tp>
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait
  2023-10-16 17:16                   ` Patrick Palka
@ 2023-10-16 20:25                     ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 20:25 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 10:16 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > This patch implements built-in trait for std::is_arithmetic.
> >
> > gcc/cp/ChangeLog:
> >
> >       * cp-trait.def: Define __is_arithmetic.
> >       * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_ARITHMETIC.
> >       * semantics.cc (trait_expr_value): Likewise.
> >       (finish_trait_expr): Likewise.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * g++.dg/ext/has-builtin-1.C: Test existence of __is_arithmetic.
> >       * g++.dg/ext/is_arithmetic.C: New test.
> >
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  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_arithmetic.C | 33 ++++++++++++++++++++++++
> >  5 files changed, 44 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_arithmetic.C
> >
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index c9d627fa782..3a7f968eae8 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3714,6 +3714,9 @@ diagnose_trait_expr (tree expr, tree args)
> >      case CPTK_IS_AGGREGATE:
> >        inform (loc, "  %qT is not an aggregate", t1);
> >        break;
> > +    case CPTK_IS_ARITHMETIC:
> > +      inform (loc, "  %qT is not an arithmetic type", t1);
> > +      break;
> >      case CPTK_IS_ARRAY:
> >        inform (loc, "  %qT is not an array", t1);
> >        break;
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index c60724e869e..b2be7b7bbd7 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
> >  DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
> >  DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
> >  DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
> > +DEFTRAIT_EXPR (IS_ARITHMETIC, "__is_arithmetic", 1)
> >  DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
> >  DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
> >  DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 83ed674b9d4..deab0134509 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >      case CPTK_IS_AGGREGATE:
> >        return CP_AGGREGATE_TYPE_P (type1);
> >
> > +    case CPTK_IS_ARITHMETIC:
> > +      return ARITHMETIC_TYPE_P (type1);
> > +
>
> For built-ins corresponding to is_arithmetic and other standard traits
> defined in terms of it (e.g.  is_scalar, is_unsigned, is_signed,
> is_fundamental) we need to make sure we preserve their behavior for
> __int128, which IIUC is currently recognized as an integral type
> (according to std::is_integral) only in GNU mode.
>
> This'll probably be subtle to get right, so if you don't mind let's
> split out the work for those built-in traits into a separate patch
> series in order to ease review of the main patch series.
>

I agree. I am postponing work on integral-related traits, so isolating
non-ready-for-review patches makes a lot of sense.

> >      case CPTK_IS_ARRAY:
> >        return type_code1 == ARRAY_TYPE;
> >
> > @@ -12406,6 +12409,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> >       return error_mark_node;
> >        break;
> >
> > +    case CPTK_IS_ARITHMETIC:
> >      case CPTK_IS_ARRAY:
> >      case CPTK_IS_BOUNDED_ARRAY:
> >      case CPTK_IS_CLASS:
> > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > index efce04fd09d..4bc85f4babb 100644
> > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > @@ -56,6 +56,9 @@
> >  #if !__has_builtin (__is_aggregate)
> >  # error "__has_builtin (__is_aggregate) failed"
> >  #endif
> > +#if !__has_builtin (__is_arithmetic)
> > +# error "__has_builtin (__is_arithmetic) failed"
> > +#endif
> >  #if !__has_builtin (__is_array)
> >  # error "__has_builtin (__is_array) failed"
> >  #endif
> > diff --git a/gcc/testsuite/g++.dg/ext/is_arithmetic.C b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> > new file mode 100644
> > index 00000000000..fd35831f646
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/is_arithmetic.C
> > @@ -0,0 +1,33 @@
> > +// { 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_arithmetic, void, false);
> > +
> > +SA_TEST_CATEGORY(__is_arithmetic, char, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, signed char, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, unsigned char, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, wchar_t, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, short, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, unsigned short, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, int, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, unsigned int, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, long, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, unsigned long, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, long long, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, unsigned long long, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, float, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, double, true);
> > +SA_TEST_CATEGORY(__is_arithmetic, long double, true);
> > +
> > +// Sanity check.
> > +SA_TEST_CATEGORY(__is_arithmetic, ClassType, false);
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 26/40] libstdc++: Optimize is_object trait performance
  2023-10-16 18:04                   ` Patrick Palka
@ 2023-10-16 20:26                     ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 20:26 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 11:04 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > This patch optimizes the performance of the is_object trait by dispatching to
> > the new __is_function and __is_reference built-in traits.
> >
> > libstdc++-v3/ChangeLog:
> >       * include/std/type_traits (is_object): Use __is_function and
> >       __is_reference built-in traits.
> >       (is_object_v): Likewise.
> >
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  libstdc++-v3/include/std/type_traits | 18 ++++++++++++++++++
> >  1 file changed, 18 insertions(+)
> >
> > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> > index bd57488824b..674d398c075 100644
> > --- a/libstdc++-v3/include/std/type_traits
> > +++ b/libstdc++-v3/include/std/type_traits
> > @@ -725,11 +725,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >      { };
> >
> >    /// is_object
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> > + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> > +  template<typename _Tp>
> > +    struct is_object
> > +    : public __bool_constant<!(__is_function(_Tp) || __is_reference(_Tp)
> > +                             || is_void<_Tp>::value)>
> > +    { };
>
> Since is_object is one of the more commonly used traits, we should
> probably just define a built-in for it.  (Either way we'd have to
> repeat the logic twice, either once in the frontend and once in
> the library, or twice in the library (is_object and is_object_v),
> so might as well do the more efficient approach).
>

Sure, I'll implement it :) Thank you for your review!

> > +#else
> >    template<typename _Tp>
> >      struct is_object
> >      : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
> >                            is_void<_Tp>>>::type
> >      { };
> > +#endif
> >
> >    template<typename>
> >      struct is_member_pointer;
> > @@ -3305,8 +3314,17 @@ template <typename _Tp>
> >    inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
> >  template <typename _Tp>
> >    inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
> > +
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function) \
> > + && _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
> > +template <typename _Tp>
> > +  inline constexpr bool is_object_v
> > +    = !(__is_function(_Tp) || __is_reference(_Tp) || is_void<_Tp>::value);
> > +#else
> >  template <typename _Tp>
> >    inline constexpr bool is_object_v = is_object<_Tp>::value;
> > +#endif
> > +
> >  template <typename _Tp>
> >    inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
> >  template <typename _Tp>
> > --
> > 2.42.0
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node
  2023-10-16 19:57                     ` Ken Matsui
@ 2023-10-16 21:06                       ` Patrick Palka
  2023-10-16 21:27                         ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 21:06 UTC (permalink / raw)
  To: Ken Matsui; +Cc: Patrick Palka, Ken Matsui, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 22462 bytes --]

On Mon, 16 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 16, 2023 at 7:55 AM Patrick Palka <ppalka@redhat.com> wrote:
> >
> > On Sun, 15 Oct 2023, Ken Matsui wrote:
> >
> > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > traits and uses the identifier node to look up the specific trait.  Rather
> > > than holding traits as keywords, we set all trait identifiers as cik_trait,
> > > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > > identifier so that we accept the use of non-function-like built-in trait
> > > identifiers.
> >
> > Thanks, this looks great!  Some review comments below.
> >
> 
> Thank you so much for your review :)
> 
> > >
> > > gcc/c-family/ChangeLog:
> > >
> > >       * c-common.cc (c_common_reswords): Remove all mappings of
> > >       built-in traits.
> > >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > >       cases for built-in traits.  Check for built-in traits via
> > >       the new cik_trait kind.
> > >       * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> > >       addr_space_t.
> > >       (struct cp_trait): New struct to hold trait information.
> > >       (cp_traits): New array to hold a mapping to all traits.
> > >       (cik_reserved_for_udlit): Rename to ...
> > >       (cik_trait): ... this.
> > >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> > >       built-in trait identifiers.
> >
> > We should mention setting IDENTIFIER_CP_INDEX as well.
> >
> 
> Thank you!
> 
> > >       (cxx_init): Call init_cp_traits function.
> > >       * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> > >       (cp_lexer_lookup_trait): New function to look up a
> > >       built-in trait by IDENTIFIER_CP_INDEX.
> > >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> > >       expression-yielding built-in trait.
> > >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > >       built-in trait.
> > >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > >       for built-in traits.
> > >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > >       type-yielding built-in traits.
> > >       (cp_parser_primary_expression): Remove all RID value cases for
> > >       built-in traits.  Handle expression-yielding built-in traits.
> > >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> > >       (cp_parser_simple_type_specifier): Remove all RID value cases
> > >       for built-in traits.  Handle type-yielding built-in traits.
> > >
> > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > >  gcc/c-family/c-common.cc  |   7 --
> > >  gcc/c-family/c-common.h   |   5 --
> > >  gcc/cp/cp-objcp-common.cc |   8 +--
> > >  gcc/cp/cp-tree.h          |  31 ++++++---
> > >  gcc/cp/lex.cc             |  21 ++++++
> > >  gcc/cp/parser.cc          | 141 ++++++++++++++++++++++++--------------
> > >  6 files changed, 139 insertions(+), 74 deletions(-)
> > >
> > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > index f044db5b797..21fd333ef57 100644
> > > --- a/gcc/c-family/c-common.cc
> > > +++ b/gcc/c-family/c-common.cc
> > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> > >    { "while",         RID_WHILE,      0 },
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -  /* An alias for __is_same.  */
> > > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > > -
> > >    /* C++ transactional memory.  */
> > >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > index 1fdba7ef3ea..051a442e0f4 100644
> > > --- a/gcc/c-family/c-common.h
> > > +++ b/gcc/c-family/c-common.h
> > > @@ -168,11 +168,6 @@ enum rid
> > >    RID_BUILTIN_LAUNDER,
> > >    RID_BUILTIN_BIT_CAST,
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -  RID_##CODE,
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -
> > >    /* C++11 */
> > >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > >
> > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > index 93b027b80ce..b1adacfec07 100644
> > > --- a/gcc/cp/cp-objcp-common.cc
> > > +++ b/gcc/cp/cp-objcp-common.cc
> > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > >       }
> > >      }
> > >
> > > +  /* Check for built-in traits.  */
> > > +  if (IDENTIFIER_TRAIT_P (id))
> > > +    return true;
> > > +
> > >    /* Also detect common reserved C++ words that aren't strictly built-in
> > >       functions.  */
> > >    switch (C_RID_CODE (id))
> > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > >      case RID_BUILTIN_ASSOC_BARRIER:
> > >      case RID_BUILTIN_BIT_CAST:
> > >      case RID_OFFSETOF:
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > >        return true;
> > >      default:
> > >        break;
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index 6e34952da99..583abb2e79a 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > >    cik_simple_op = 4, /* Non-assignment operator name.  */
> > >    cik_assign_op = 5, /* An assignment operator name.  */
> > >    cik_conv_op = 6,   /* Conversion operator name.  */
> > > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > > +  cik_trait = 7,     /* Built-in trait name.  */
> > >    cik_max
> > >  };
> > >
> > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > >      & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > >  /* True if this identifier is for any operator name (including
> > > -   conversions).  Value 4, 5, 6 or 7.  */
> > > +   conversions).  Value 4, 5, or 6.  */
> > >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > >
> > >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> > >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > >     & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > >  /* True if this identifier is the name of a type-conversion
> > > -   operator.  Value 7.  */
> > > +   operator.  Value 6.  */
> > >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> > >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> > >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> > >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > >
> > > +/* True if this identifier is the name of a built-in trait.  */
> > > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > > +
> > >  /* True if this identifier is a new or delete operator.  */
> > >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> > >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > > @@ -1375,16 +1381,25 @@ struct GTY (()) tree_argument_pack_select {
> > >    int index;
> > >  };
> > >
> > > -/* The different kinds of traits that we encounter.  */
> > > -
> > > -enum cp_trait_kind
> > > -{
> > > +/* The different kinds of traits that we encounter.  The size is limited to
> > > +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> > > +enum cp_trait_kind : addr_space_t {
> > >  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > >    CPTK_##CODE,
> > >  #include "cp-trait.def"
> > >  #undef DEFTRAIT
> > >  };
> > >
> > > +/* The trait type.  */
> > > +struct cp_trait {
> > > +  short arity;
> > > +  cp_trait_kind kind;
> > > +  bool type;
> >
> > Could we also store the const char* name of each trait here, so that ...
> >
> > > +};
> > > +
> > > +/* The trait table.  */
> > > +extern const struct cp_trait cp_traits[];
> > > +
> > >  /* The types that we are processing.  */
> > >  #define TRAIT_EXPR_TYPE1(NODE) \
> > >    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > index 64bcfb18196..16a82a12a02 100644
> > > --- a/gcc/cp/lex.cc
> > > +++ b/gcc/cp/lex.cc
> > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> > >  #include "langhooks.h"
> > >
> > >  static int interface_strcmp (const char *);
> > > +static void init_cp_traits (void);
> > >  static void init_cp_pragma (void);
> > >
> > >  static tree parse_strconst_pragma (const char *, int);
> > > @@ -283,6 +284,25 @@ init_reswords (void)
> > >      }
> > >  }
> > >
> > > +/* Initialize the C++ traits.  */
> > > +static void
> > > +init_cp_traits (void)
> > > +{
> > > +  tree id;
> > > +
> > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > +  id = get_identifier (NAME); \
> > > +  IDENTIFIER_CP_INDEX (id) = CPTK_##CODE; \
> > > +  set_identifier_kind (id, cik_trait);
> > > +#include "cp/cp-trait.def"
> > > +#undef DEFTRAIT
> >
> > ... we could replace this straight-line code with a loop over cp_traits?
> > It'd make cp_traits bigger but init_cp_traits should get much smaller,
> > which should be a net win in terms of binary size.
> >
> 
> I see. Since we know the number of iterations would be up to 255 and
> the inner statements are only 3 and pretty simple/small, I think it is
> likely that we will benefit from loop unrolling. But do we want to
> prioritize the binary size over the possible performance improvements?

That's something I'd let the compiler decide on since it has a
target-specific understanding of such tradeoffs :) And by writing it as
a loop the compiler is free to unroll it if it decides doing so is
worthwhile, whereas the other way around is not really possible here.
So from that perspective it seems using a loop is the better default
choice.

> 
> > > +
> > > +  /* An alias for __is_same.  */
> > > +  id = get_identifier ("__is_same_as");
> > > +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> > > +  set_identifier_kind (id, cik_trait);
> > > +}
> > > +
> > >  static void
> > >  init_cp_pragma (void)
> > >  {
> > > @@ -324,6 +344,7 @@ cxx_init (void)
> > >    input_location = BUILTINS_LOCATION;
> > >
> > >    init_reswords ();
> > > +  init_cp_traits ();
> > >    init_tree ();
> > >    init_cp_semantics ();
> > >    init_operators ();
> > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > index f3abae716fe..eba5272be03 100644
> > > --- a/gcc/cp/parser.cc
> > > +++ b/gcc/cp/parser.cc
> > > @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
> > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > >  static void cp_lexer_stop_debugging
> > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > +static const cp_trait *cp_lexer_lookup_trait
> > > +  (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > +  (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > +  (const cp_token *);
> > >
> > >  static cp_token_cache *cp_token_cache_new
> > >    (cp_token *, cp_token *);
> > > @@ -279,6 +285,19 @@ static FILE *cp_lexer_debug_stream;
> > >     sizeof, typeof, or alignof.  */
> > >  int cp_unevaluated_operand;
> > >
> > > +/* The trait table, declared in cp-tree.h.  */
> > > +const cp_trait cp_traits[] =
> > > +{
> > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > +  { ARITY, CPTK_##CODE, (TCC == tcc_type) },
> > > +#include "cp-trait.def"
> > > +#undef DEFTRAIT
> > > +};
> > > +/* The trait table cannot have more than 255 (addr_space_t) entries since
> > > +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> > > +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> > > +              "cp_traits array cannot have more than 255 entries");
> > > +
> > >  /* Dump up to NUM tokens in BUFFER to FILE starting with token
> > >     START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
> > >     first token in BUFFER.  If NUM is 0, dump all the tokens.  If
> > > @@ -1167,12 +1186,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > >      case RID_CONSTEVAL:
> > >        return true;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > -      return true;
> > > -
> > >      default:
> > >        if (keyword >= RID_FIRST_INT_N
> > >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > @@ -1182,6 +1195,48 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > >      }
> > >  }
> > >
> > > +/* Look ups the corresponding built-in trait if a given token is
> > > +   a built-in trait.  Otherwise, returns nullptr.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait (const cp_token *token)
> > > +{
> > > +  tree id = token->u.value;
> > > +
> > > +  if (token->type == CPP_NAME
> > > +      && TREE_CODE (id) == IDENTIFIER_NODE
> >
> > The value of a CPP_NAME token is always an IDENTIFIER_NODE, so this
> > check should be redundant.  Also we should access the u.value union member
> > only after the CPP_NAME check, since for some other token kinds u.value
> > isn't the active member (and reading from it would be undefined behavior
> > strictly speaking).
> >
> 
> Thank you!
> 
> > > +      && IDENTIFIER_TRAIT_P (id))
> > > +    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
> > > +
> > > +  return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is an expression-yielding
> > > +   built-in trait.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > +{
> > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > +  if (trait && !trait->type)
> > > +    return trait;
> > > +
> > > +  return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is a type-yielding
> > > +   built-in trait.  */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > +{
> > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > +  if (trait && trait->type)
> > > +    return trait;
> > > +
> > > +  return nullptr;
> > > +}
> > > +
> > >  /* Return true if the next token is a keyword for a decl-specifier.  */
> > >
> > >  static bool
> > > @@ -1190,6 +1245,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > >    cp_token *token;
> > >
> > >    token = cp_lexer_peek_token (lexer);
> > > +  if (cp_lexer_lookup_trait_type (token))
> > > +    return true;
> > >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> > >  }
> > >
> > > @@ -2854,7 +2911,7 @@ static void cp_parser_late_parsing_default_args
> > >  static tree cp_parser_sizeof_operand
> > >    (cp_parser *, enum rid);
> > >  static cp_expr cp_parser_trait
> > > -  (cp_parser *, enum rid);
> > > +  (cp_parser *, const cp_trait *);
> > >  static bool cp_parser_declares_only_class_p
> > >    (cp_parser *);
> > >  static void cp_parser_set_storage_class
> > > @@ -6021,12 +6078,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > >       case RID_OFFSETOF:
> > >         return cp_parser_builtin_offsetof (parser);
> > >
> > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > -     case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_EXPR
> > > -       return cp_parser_trait (parser, token->keyword);
> > > -
> > >       // C++ concepts
> > >       case RID_REQUIRES:
> > >         return cp_parser_requires_expression (parser);
> > > @@ -6065,6 +6116,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > >        `::' as the beginning of a qualified-id, or the "operator"
> > >        keyword.  */
> > >      case CPP_NAME:
> > > +      {
> > > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > +     if (trait)
> >
> > A tiny nit, but we could remove the extra block scope here by doing
> > 'if (const cp_trait* trait = ...)' instead.
> >
> 
> Thank you!
> 
> > > +       return cp_parser_trait (parser, trait);
> > > +      }
> > > +      /* FALLTHRU */
> > >      case CPP_SCOPE:
> > >      case CPP_TEMPLATE_ID:
> > >      case CPP_NESTED_NAME_SPECIFIER:
> > > @@ -11033,28 +11090,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > >  /* Parse a builtin trait expression or type.  */
> > >
> > >  static cp_expr
> > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > >  {
> > > -  cp_trait_kind kind;
> > >    tree type1, type2 = NULL_TREE;
> > > -  bool binary = false;
> > > -  bool variadic = false;
> > > -  bool type = false;
> > > -
> > > -  switch (keyword)
> > > -    {
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > -    case RID_##CODE:                  \
> > > -      kind = CPTK_##CODE;             \
> > > -      binary = (ARITY == 2);          \
> > > -      variadic = (ARITY == -1);               \
> > > -      type = (TCC == tcc_type);               \
> > > -      break;
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > > -    default:
> > > -      gcc_unreachable ();
> > > -    }
> > > +  const bool binary = (trait->arity == 2);
> > > +  const bool variadic = (trait->arity == -1);
> >
> > Could we continue defining the local variables 'kind' and 'type' here so
> > that we don't have to adjust their uses in the rest of the function?
> > That should yield a smaller diff for this function.
> >
> 
> Yes, I will update this patch. Thank you!
> 
> > >
> > >    /* Get location of initial token.  */
> > >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > @@ -11063,12 +11103,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >    cp_lexer_consume_token (parser->lexer);
> > >
> > >    matching_parens parens;
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> > >    else
> > >      parens.require_open (parser);
> > >
> > > -  if (kind == CPTK_IS_DEDUCIBLE)
> > > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> > >      {
> > >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > >        type1 = cp_parser_id_expression (parser,
> > > @@ -11079,7 +11119,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >                                      /*optional_p=*/false);
> > >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > >      }
> > > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      /* __type_pack_element takes an expression as its first argument and uses
> > >         template-id syntax instead of function call syntax (for consistency
> > >         with Clang).  We special case these properties of __type_pack_element
> > > @@ -11094,7 +11134,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >    if (type1 == error_mark_node)
> > >      return error_mark_node;
> > >
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      {
> > >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > @@ -11144,7 +11184,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >      }
> > >
> > >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > >      /* cp_parser_enclosed_template_argument_list above already took care
> > >         of parsing the closing '>'.  */;
> > >    else
> > > @@ -11158,17 +11198,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >
> > >    /* Complete the trait expression, which may mean either processing
> > >       the trait expr now or saving it for template instantiation.  */
> > > -  switch (kind)
> > > +  switch (trait->kind)
> > >      {
> > >      case CPTK_BASES:
> > >        return cp_expr (finish_bases (type1, false), trait_loc);
> > >      case CPTK_DIRECT_BASES:
> > >        return cp_expr (finish_bases (type1, true), trait_loc);
> > >      default:
> > > -      if (type)
> > > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > +      if (trait->type)
> > > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > >        else
> > > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > >      }
> > >  }
> > >
> > > @@ -20081,20 +20121,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > >
> > >        return type;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > -    case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > -      type = cp_parser_trait (parser, token->keyword);
> > > +    default:
> > > +      break;
> > > +    }
> > > +
> > > +  /* If token is a type-yielding built-in traits, parse it.  */
> > > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > +  if (trait)
> > > +    {
> > > +      type = cp_parser_trait (parser, trait);
> > >        if (decl_specs)
> > >       cp_parser_set_decl_spec_type (decl_specs, type,
> > >                                     token,
> > >                                     /*type_definition_p=*/false);
> > >
> > >        return type;
> > > -
> > > -    default:
> > > -      break;
> > >      }
> > >
> > >    /* If token is an already-parsed decltype not followed by ::,
> > > --
> > > 2.42.0
> > >
> > >
> >
> 
> 

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically
  2023-10-16 20:11                     ` Ken Matsui
@ 2023-10-16 21:12                       ` Patrick Palka
  2023-10-16 21:30                         ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-16 21:12 UTC (permalink / raw)
  To: Ken Matsui; +Cc: Patrick Palka, Ken Matsui, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 22676 bytes --]

On Mon, 16 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 16, 2023 at 8:17 AM Patrick Palka <ppalka@redhat.com> wrote:
> >
> > On Sun, 15 Oct 2023, Ken Matsui wrote:
> >
> > > This patch sorts built-in traits alphabetically for better code
> > > readability.
> >
> > Hmm, I'm not sure if we still want/need this change with this current
> > approach.  IIUC gperf would sort the trait names when generating the
> > hash table code, and so we wanted a more consistent mapping from the
> > cp-trait.def file to the generated code.  But with this current
> > non-gperf approach I'm inclined to leave the existing ordering alone
> > for sake of simplicity, and I kind of like that in cp-trait.def we
> > currently group all expression-yielding traits together and all
> > type-yielding traits together; that seems like a more natural layout
> > than plain alphabetical sorting.
> >
> 
> I see. But this patch is crucial for me to keep all my existing
> patches almost conflict-free against rebase, including drop, add, and
> edit like you suggested to split integral-related patches. Without
> this patch and alphabetical order, I will need to put a new trait in a
> random place not close to surrounding commits, as Git relates close
> lines when it finds conflicts. When I merged all my patches into one
> patch series, I needed to fix conflicts for all my patches almost
> every time I rebased. Both thinking of the random place and fixing the
> conflicts of all patches would definitely not be desirable. Would you
> think we should drop this patch?

Fair enough, I'm all for keeping this patch and alphabetizing then :)

> 
> > >
> > > gcc/cp/ChangeLog:
> > >
> > >       * constraint.cc (diagnose_trait_expr): Sort built-in traits
> > >       alphabetically.
> > >       * cp-trait.def: Likewise.
> > >       * semantics.cc (trait_expr_value): Likewise.
> > >       (finish_trait_expr): Likewise.
> > >       (finish_trait_type): Likewise.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >       * g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> > >
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > >  gcc/cp/constraint.cc                     | 68 ++++++++---------
> > >  gcc/cp/cp-trait.def                      | 10 +--
> > >  gcc/cp/semantics.cc                      | 94 ++++++++++++------------
> > >  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
> > >  4 files changed, 121 insertions(+), 121 deletions(-)
> > >
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index c9e4e7043cd..722fc334e6f 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
> > >      case CPTK_HAS_TRIVIAL_DESTRUCTOR:
> > >        inform (loc, "  %qT is not trivially destructible", t1);
> > >        break;
> > > +    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > +      inform (loc, "  %qT does not have unique object representations", t1);
> > > +      break;
> > >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > >        inform (loc, "  %qT does not have a virtual destructor", t1);
> > >        break;
> > >      case CPTK_IS_ABSTRACT:
> > >        inform (loc, "  %qT is not an abstract class", t1);
> > >        break;
> > > +    case CPTK_IS_AGGREGATE:
> > > +      inform (loc, "  %qT is not an aggregate", t1);
> > > +      break;
> > > +    case CPTK_IS_ASSIGNABLE:
> > > +      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > > +      break;
> > >      case CPTK_IS_BASE_OF:
> > >        inform (loc, "  %qT is not a base of %qT", t1, t2);
> > >        break;
> > >      case CPTK_IS_CLASS:
> > >        inform (loc, "  %qT is not a class", t1);
> > >        break;
> > > +    case CPTK_IS_CONSTRUCTIBLE:
> > > +      if (!t2)
> > > +    inform (loc, "  %qT is not default constructible", t1);
> > > +      else
> > > +    inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > > +      break;
> > > +    case CPTK_IS_CONVERTIBLE:
> > > +      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > > +      break;
> > >      case CPTK_IS_EMPTY:
> > >        inform (loc, "  %qT is not an empty class", t1);
> > >        break;
> > > @@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
> > >      case CPTK_IS_LITERAL_TYPE:
> > >        inform (loc, "  %qT is not a literal type", t1);
> > >        break;
> > > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > +      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > > +      break;
> > > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > +      if (!t2)
> > > +     inform (loc, "  %qT is not nothrow default constructible", t1);
> > > +      else
> > > +     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > > +      break;
> > > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > +       inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > > +      break;
> > >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> > >        inform (loc, "  %qT is not pointer-interconvertible base of %qT",
> > >             t1, t2);
> > > @@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
> > >      case CPTK_IS_TRIVIAL:
> > >        inform (loc, "  %qT is not a trivial type", t1);
> > >        break;
> > > -    case CPTK_IS_UNION:
> > > -      inform (loc, "  %qT is not a union", t1);
> > > -      break;
> > > -    case CPTK_IS_AGGREGATE:
> > > -      inform (loc, "  %qT is not an aggregate", t1);
> > > -      break;
> > > -    case CPTK_IS_TRIVIALLY_COPYABLE:
> > > -      inform (loc, "  %qT is not trivially copyable", t1);
> > > -      break;
> > > -    case CPTK_IS_ASSIGNABLE:
> > > -      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > > -      break;
> > >      case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > >        inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
> > >        break;
> > > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > -      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > > -      break;
> > > -    case CPTK_IS_CONSTRUCTIBLE:
> > > -      if (!t2)
> > > -     inform (loc, "  %qT is not default constructible", t1);
> > > -      else
> > > -     inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > > -      break;
> > >      case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > >        if (!t2)
> > >       inform (loc, "  %qT is not trivially default constructible", t1);
> > >        else
> > >       inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
> > >        break;
> > > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > -      if (!t2)
> > > -     inform (loc, "  %qT is not nothrow default constructible", t1);
> > > -      else
> > > -     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > > -      break;
> > > -    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > -      inform (loc, "  %qT does not have unique object representations", t1);
> > > -      break;
> > > -    case CPTK_IS_CONVERTIBLE:
> > > -      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > > +    case CPTK_IS_TRIVIALLY_COPYABLE:
> > > +      inform (loc, "  %qT is not trivially copyable", t1);
> > >        break;
> > > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > -     inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > > +    case CPTK_IS_UNION:
> > > +      inform (loc, "  %qT is not a union", t1);
> > >        break;
> > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > >        inform (loc, "  %qT is not a reference that binds to a temporary "
> > > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > > index 8b7fece0cc8..0e48e64b8dd 100644
> > > --- a/gcc/cp/cp-trait.def
> > > +++ b/gcc/cp/cp-trait.def
> > > @@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
> > >  DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
> > > -DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> > > -
> > >  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> > > -DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> > >  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> > > -DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> > > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> > >  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> > > +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
> > > +
> > > +/* FIXME Added space to avoid direct usage in GCC 13.  */
> > > +DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> > >
> > >  /* These traits yield a type pack, not a type, and are represented by
> > >     cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
> > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > > index 80ef1364e33..782aa515da0 100644
> > > --- a/gcc/cp/semantics.cc
> > > +++ b/gcc/cp/semantics.cc
> > > @@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >                     && classtype_has_nothrow_assign_or_copy_p (type1,
> > >                                                                true))));
> > >
> > > -    case CPTK_HAS_TRIVIAL_ASSIGN:
> > > -      /* ??? The standard seems to be missing the "or array of such a class
> > > -      type" wording for this trait.  */
> > > -      type1 = strip_array_types (type1);
> > > -      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > > -           && (trivial_type_p (type1)
> > > -                 || (CLASS_TYPE_P (type1)
> > > -                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > > -
> > >      case CPTK_HAS_NOTHROW_CONSTRUCTOR:
> > >        type1 = strip_array_types (type1);
> > >        return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
> > > @@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >                 && maybe_instantiate_noexcept (t)
> > >                 && TYPE_NOTHROW_P (TREE_TYPE (t))));
> > >
> > > -    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > > -      type1 = strip_array_types (type1);
> > > -      return (trivial_type_p (type1)
> > > -           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > > -
> > >      case CPTK_HAS_NOTHROW_COPY:
> > >        type1 = strip_array_types (type1);
> > >        return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
> > >             || (CLASS_TYPE_P (type1)
> > >                 && classtype_has_nothrow_assign_or_copy_p (type1, false)));
> > >
> > > +    case CPTK_HAS_TRIVIAL_ASSIGN:
> > > +      /* ??? The standard seems to be missing the "or array of such a class
> > > +      type" wording for this trait.  */
> > > +      type1 = strip_array_types (type1);
> > > +      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > > +           && (trivial_type_p (type1)
> > > +                 || (CLASS_TYPE_P (type1)
> > > +                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > > +
> > > +    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > > +      type1 = strip_array_types (type1);
> > > +      return (trivial_type_p (type1)
> > > +           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > > +
> > >      case CPTK_HAS_TRIVIAL_COPY:
> > >        /* ??? The standard seems to be missing the "or array of such a class
> > >        type" wording for this trait.  */
> > > @@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >             || (CLASS_TYPE_P (type1)
> > >                 && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
> > >
> > > -    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > -      return type_has_virtual_destructor (type1);
> > > -
> > >      case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > >        return type_has_unique_obj_representations (type1);
> > >
> > > +    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > +      return type_has_virtual_destructor (type1);
> > > +
> > >      case CPTK_IS_ABSTRACT:
> > >        return ABSTRACT_CLASS_TYPE_P (type1);
> > >
> > >      case CPTK_IS_AGGREGATE:
> > >        return CP_AGGREGATE_TYPE_P (type1);
> > >
> > > +    case CPTK_IS_ASSIGNABLE:
> > > +      return is_xible (MODIFY_EXPR, type1, type2);
> > > +
> > >      case CPTK_IS_BASE_OF:
> > >        return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
> > >             && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
> > > @@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >      case CPTK_IS_CLASS:
> > >        return NON_UNION_CLASS_TYPE_P (type1);
> > >
> > > +    case CPTK_IS_CONSTRUCTIBLE:
> > > +      return is_xible (INIT_EXPR, type1, type2);
> > > +
> > > +    case CPTK_IS_CONVERTIBLE:
> > > +      return is_convertible (type1, type2);
> > > +
> > >      case CPTK_IS_EMPTY:
> > >        return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
> > >
> > > @@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >      case CPTK_IS_LITERAL_TYPE:
> > >        return literal_type_p (type1);
> > >
> > > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > +      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > > +
> > > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > +      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > > +
> > > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > +      return is_nothrow_convertible (type1, type2);
> > > +
> > >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> > >        return pointer_interconvertible_base_of_p (type1, type2);
> > >
> > > @@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >      case CPTK_IS_UNION:
> > >        return type_code1 == UNION_TYPE;
> > >
> > > -    case CPTK_IS_ASSIGNABLE:
> > > -      return is_xible (MODIFY_EXPR, type1, type2);
> > > -
> > > -    case CPTK_IS_CONSTRUCTIBLE:
> > > -      return is_xible (INIT_EXPR, type1, type2);
> > > -
> > > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > -      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > > -
> > > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > -      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > > -
> > > -    case CPTK_IS_CONVERTIBLE:
> > > -      return is_convertible (type1, type2);
> > > -
> > > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > -      return is_nothrow_convertible (type1, type2);
> > > -
> > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > >        return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
> > >
> > > @@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > >       return error_mark_node;
> > >        break;
> > >
> > > +    case CPTK_IS_ABSTRACT:
> > >      case CPTK_IS_EMPTY:
> > >      case CPTK_IS_POLYMORPHIC:
> > > -    case CPTK_IS_ABSTRACT:
> > >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > >        if (!check_trait_type (type1, /* kind = */ 3))
> > >       return error_mark_node;
> > > @@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > >       return error_mark_node;
> > >        break;
> > >
> > > -    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > > -    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > > +    case CPTK_IS_CONVERTIBLE:
> > >      case CPTK_IS_NOTHROW_ASSIGNABLE:
> > >      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > -    case CPTK_IS_CONVERTIBLE:
> > >      case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > +    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > > +    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > >      case CPTK_REF_CONVERTS_FROM_TEMPORARY:
> > >        if (!check_trait_type (type1)
> > > @@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > >
> > >      case CPTK_IS_CLASS:
> > >      case CPTK_IS_ENUM:
> > > -    case CPTK_IS_UNION:
> > >      case CPTK_IS_SAME:
> > > +    case CPTK_IS_UNION:
> > >        break;
> > >
> > >      case CPTK_IS_LAYOUT_COMPATIBLE:
> > > @@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
> > >
> > >    switch (kind)
> > >      {
> > > -    case CPTK_UNDERLYING_TYPE:
> > > -      return finish_underlying_type (type1);
> > > -
> > >      case CPTK_REMOVE_CV:
> > >        return cv_unqualified (type1);
> > >
> > > -    case CPTK_REMOVE_REFERENCE:
> > > +    case CPTK_REMOVE_CVREF:
> > >        if (TYPE_REF_P (type1))
> > >       type1 = TREE_TYPE (type1);
> > > -      return type1;
> > > +      return cv_unqualified (type1);
> > >
> > > -    case CPTK_REMOVE_CVREF:
> > > +    case CPTK_REMOVE_REFERENCE:
> > >        if (TYPE_REF_P (type1))
> > >       type1 = TREE_TYPE (type1);
> > > -      return cv_unqualified (type1);
> > > +      return type1;
> > >
> > >      case CPTK_TYPE_PACK_ELEMENT:
> > >        return finish_type_pack_element (type1, type2, complain);
> > >
> > > +    case CPTK_UNDERLYING_TYPE:
> > > +      return finish_underlying_type (type1);
> > > +
> > >  #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > >      case CPTK_##CODE:
> > >  #include "cp-trait.def"
> > > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > index f343e153e56..2223f08a628 100644
> > > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > @@ -8,9 +8,21 @@
> > >  #if !__has_builtin (__builtin_bit_cast)
> > >  # error "__has_builtin (__builtin_bit_cast) failed"
> > >  #endif
> > > +#if !__has_builtin (__builtin_is_constant_evaluated)
> > > +# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > > +#endif
> > > +#if !__has_builtin (__builtin_is_corresponding_member)
> > > +# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > > +#endif
> > > +#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > > +# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > > +#endif
> > >  #if !__has_builtin (__builtin_launder)
> > >  # error "__has_builtin (__builtin_launder) failed"
> > >  #endif
> > > +#if !__has_builtin (__builtin_source_location)
> > > +# error "__has_builtin (__builtin_source_location) failed"
> > > +#endif
> > >  #if !__has_builtin (__has_nothrow_assign)
> > >  # error "__has_builtin (__has_nothrow_assign) failed"
> > >  #endif
> > > @@ -44,12 +56,21 @@
> > >  #if !__has_builtin (__is_aggregate)
> > >  # error "__has_builtin (__is_aggregate) failed"
> > >  #endif
> > > +#if !__has_builtin (__is_assignable)
> > > +# error "__has_builtin (__is_assignable) failed"
> > > +#endif
> > >  #if !__has_builtin (__is_base_of)
> > >  # error "__has_builtin (__is_base_of) failed"
> > >  #endif
> > >  #if !__has_builtin (__is_class)
> > >  # error "__has_builtin (__is_class) failed"
> > >  #endif
> > > +#if !__has_builtin (__is_constructible)
> > > +# error "__has_builtin (__is_constructible) failed"
> > > +#endif
> > > +#if !__has_builtin (__is_convertible)
> > > +# error "__has_builtin (__is_convertible) failed"
> > > +#endif
> > >  #if !__has_builtin (__is_empty)
> > >  # error "__has_builtin (__is_empty) failed"
> > >  #endif
> > > @@ -65,6 +86,15 @@
> > >  #if !__has_builtin (__is_literal_type)
> > >  # error "__has_builtin (__is_literal_type) failed"
> > >  #endif
> > > +#if !__has_builtin (__is_nothrow_assignable)
> > > +# error "__has_builtin (__is_nothrow_assignable) failed"
> > > +#endif
> > > +#if !__has_builtin (__is_nothrow_constructible)
> > > +# error "__has_builtin (__is_nothrow_constructible) failed"
> > > +#endif
> > > +#if !__has_builtin (__is_nothrow_convertible)
> > > +# error "__has_builtin (__is_nothrow_convertible) failed"
> > > +#endif
> > >  #if !__has_builtin (__is_pointer_interconvertible_base_of)
> > >  # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
> > >  #endif
> > > @@ -98,51 +128,21 @@
> > >  #if !__has_builtin (__is_union)
> > >  # error "__has_builtin (__is_union) failed"
> > >  #endif
> > > -#if !__has_builtin (__underlying_type)
> > > -# error "__has_builtin (__underlying_type) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_assignable)
> > > -# error "__has_builtin (__is_assignable) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_constructible)
> > > -# error "__has_builtin (__is_constructible) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_nothrow_assignable)
> > > -# error "__has_builtin (__is_nothrow_assignable) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_nothrow_constructible)
> > > -# error "__has_builtin (__is_nothrow_constructible) failed"
> > > -#endif
> > >  #if !__has_builtin (__reference_constructs_from_temporary)
> > >  # error "__has_builtin (__reference_constructs_from_temporary) failed"
> > >  #endif
> > >  #if !__has_builtin (__reference_converts_from_temporary)
> > >  # error "__has_builtin (__reference_converts_from_temporary) failed"
> > >  #endif
> > > -#if !__has_builtin (__builtin_is_constant_evaluated)
> > > -# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > > -#endif
> > > -#if !__has_builtin (__builtin_source_location)
> > > -# error "__has_builtin (__builtin_source_location) failed"
> > > -#endif
> > > -#if !__has_builtin (__builtin_is_corresponding_member)
> > > -# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > > -#endif
> > > -#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > > -# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_convertible)
> > > -# error "__has_builtin (__is_convertible) failed"
> > > -#endif
> > > -#if !__has_builtin (__is_nothrow_convertible)
> > > -# error "__has_builtin (__is_nothrow_convertible) failed"
> > > -#endif
> > >  #if !__has_builtin (__remove_cv)
> > >  # error "__has_builtin (__remove_cv) failed"
> > >  #endif
> > > +#if !__has_builtin (__remove_cvref)
> > > +# error "__has_builtin (__remove_cvref) failed"
> > > +#endif
> > >  #if !__has_builtin (__remove_reference)
> > >  # error "__has_builtin (__remove_reference) failed"
> > >  #endif
> > > -#if !__has_builtin (__remove_cvref)
> > > -# error "__has_builtin (__remove_cvref) failed"
> > > +#if !__has_builtin (__underlying_type)
> > > +# error "__has_builtin (__underlying_type) failed"
> > >  #endif
> > > --
> > > 2.42.0
> > >
> > >
> >
> 
> 

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node
  2023-10-16 21:06                       ` Patrick Palka
@ 2023-10-16 21:27                         ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 21:27 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 2:06 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Mon, 16 Oct 2023, Ken Matsui wrote:
>
> > On Mon, Oct 16, 2023 at 7:55 AM Patrick Palka <ppalka@redhat.com> wrote:
> > >
> > > On Sun, 15 Oct 2023, Ken Matsui wrote:
> > >
> > > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > > traits and uses the identifier node to look up the specific trait.  Rather
> > > > than holding traits as keywords, we set all trait identifiers as cik_trait,
> > > > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > > > identifier so that we accept the use of non-function-like built-in trait
> > > > identifiers.
> > >
> > > Thanks, this looks great!  Some review comments below.
> > >
> >
> > Thank you so much for your review :)
> >
> > > >
> > > > gcc/c-family/ChangeLog:
> > > >
> > > >       * c-common.cc (c_common_reswords): Remove all mappings of
> > > >       built-in traits.
> > > >       * c-common.h (enum rid): Remove all RID values for built-in traits.
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >       * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > > >       cases for built-in traits.  Check for built-in traits via
> > > >       the new cik_trait kind.
> > > >       * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> > > >       addr_space_t.
> > > >       (struct cp_trait): New struct to hold trait information.
> > > >       (cp_traits): New array to hold a mapping to all traits.
> > > >       (cik_reserved_for_udlit): Rename to ...
> > > >       (cik_trait): ... this.
> > > >       (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > > >       (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > > >       * lex.cc (init_cp_traits): New function to set cik_trait for all
> > > >       built-in trait identifiers.
> > >
> > > We should mention setting IDENTIFIER_CP_INDEX as well.
> > >
> >
> > Thank you!
> >
> > > >       (cxx_init): Call init_cp_traits function.
> > > >       * parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> > > >       (cp_lexer_lookup_trait): New function to look up a
> > > >       built-in trait by IDENTIFIER_CP_INDEX.
> > > >       (cp_lexer_lookup_trait_expr): Likewise, look up an
> > > >       expression-yielding built-in trait.
> > > >       (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > > >       built-in trait.
> > > >       (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > > >       for built-in traits.
> > > >       (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > > >       type-yielding built-in traits.
> > > >       (cp_parser_primary_expression): Remove all RID value cases for
> > > >       built-in traits.  Handle expression-yielding built-in traits.
> > > >       (cp_parser_trait): Handle cp_trait instead of enum rid.
> > > >       (cp_parser_simple_type_specifier): Remove all RID value cases
> > > >       for built-in traits.  Handle type-yielding built-in traits.
> > > >
> > > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > > ---
> > > >  gcc/c-family/c-common.cc  |   7 --
> > > >  gcc/c-family/c-common.h   |   5 --
> > > >  gcc/cp/cp-objcp-common.cc |   8 +--
> > > >  gcc/cp/cp-tree.h          |  31 ++++++---
> > > >  gcc/cp/lex.cc             |  21 ++++++
> > > >  gcc/cp/parser.cc          | 141 ++++++++++++++++++++++++--------------
> > > >  6 files changed, 139 insertions(+), 74 deletions(-)
> > > >
> > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > > index f044db5b797..21fd333ef57 100644
> > > > --- a/gcc/c-family/c-common.cc
> > > > +++ b/gcc/c-family/c-common.cc
> > > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > > >    { "wchar_t",               RID_WCHAR,      D_CXXONLY },
> > > >    { "while",         RID_WHILE,      0 },
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -  { NAME,            RID_##CODE,     D_CXXONLY },
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -  /* An alias for __is_same.  */
> > > > -  { "__is_same_as",  RID_IS_SAME,    D_CXXONLY },
> > > > -
> > > >    /* C++ transactional memory.  */
> > > >    { "synchronized",  RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > > >    { "atomic_noexcept",       RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > > index 1fdba7ef3ea..051a442e0f4 100644
> > > > --- a/gcc/c-family/c-common.h
> > > > +++ b/gcc/c-family/c-common.h
> > > > @@ -168,11 +168,6 @@ enum rid
> > > >    RID_BUILTIN_LAUNDER,
> > > >    RID_BUILTIN_BIT_CAST,
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -  RID_##CODE,
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -
> > > >    /* C++11 */
> > > >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > > >
> > > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > > index 93b027b80ce..b1adacfec07 100644
> > > > --- a/gcc/cp/cp-objcp-common.cc
> > > > +++ b/gcc/cp/cp-objcp-common.cc
> > > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > > >       }
> > > >      }
> > > >
> > > > +  /* Check for built-in traits.  */
> > > > +  if (IDENTIFIER_TRAIT_P (id))
> > > > +    return true;
> > > > +
> > > >    /* Also detect common reserved C++ words that aren't strictly built-in
> > > >       functions.  */
> > > >    switch (C_RID_CODE (id))
> > > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > > >      case RID_BUILTIN_ASSOC_BARRIER:
> > > >      case RID_BUILTIN_BIT_CAST:
> > > >      case RID_OFFSETOF:
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > >        return true;
> > > >      default:
> > > >        break;
> > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > > index 6e34952da99..583abb2e79a 100644
> > > > --- a/gcc/cp/cp-tree.h
> > > > +++ b/gcc/cp/cp-tree.h
> > > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > > >    cik_simple_op = 4, /* Non-assignment operator name.  */
> > > >    cik_assign_op = 5, /* An assignment operator name.  */
> > > >    cik_conv_op = 6,   /* Conversion operator name.  */
> > > > -  cik_reserved_for_udlit = 7,        /* Not yet in use  */
> > > > +  cik_trait = 7,     /* Built-in trait name.  */
> > > >    cik_max
> > > >  };
> > > >
> > > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > > >      & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > >  /* True if this identifier is for any operator name (including
> > > > -   conversions).  Value 4, 5, 6 or 7.  */
> > > > +   conversions).  Value 4, 5, or 6.  */
> > > >  #define IDENTIFIER_ANY_OP_P(NODE)            \
> > > > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > > > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > > >
> > > >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> > > >  #define IDENTIFIER_OVL_OP_P(NODE)            \
> > > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > > >     & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > >  /* True if this identifier is the name of a type-conversion
> > > > -   operator.  Value 7.  */
> > > > +   operator.  Value 6.  */
> > > >  #define IDENTIFIER_CONV_OP_P(NODE)           \
> > > >    (IDENTIFIER_ANY_OP_P (NODE)                        \
> > > >     & IDENTIFIER_KIND_BIT_1 (NODE)            \
> > > >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > > >
> > > > +/* True if this identifier is the name of a built-in trait.  */
> > > > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > > > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > > > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > > > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > > > +
> > > >  /* True if this identifier is a new or delete operator.  */
> > > >  #define IDENTIFIER_NEWDEL_OP_P(NODE)         \
> > > >    (IDENTIFIER_OVL_OP_P (NODE)                        \
> > > > @@ -1375,16 +1381,25 @@ struct GTY (()) tree_argument_pack_select {
> > > >    int index;
> > > >  };
> > > >
> > > > -/* The different kinds of traits that we encounter.  */
> > > > -
> > > > -enum cp_trait_kind
> > > > -{
> > > > +/* The different kinds of traits that we encounter.  The size is limited to
> > > > +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> > > > +enum cp_trait_kind : addr_space_t {
> > > >  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > >    CPTK_##CODE,
> > > >  #include "cp-trait.def"
> > > >  #undef DEFTRAIT
> > > >  };
> > > >
> > > > +/* The trait type.  */
> > > > +struct cp_trait {
> > > > +  short arity;
> > > > +  cp_trait_kind kind;
> > > > +  bool type;
> > >
> > > Could we also store the const char* name of each trait here, so that ...
> > >
> > > > +};
> > > > +
> > > > +/* The trait table.  */
> > > > +extern const struct cp_trait cp_traits[];
> > > > +
> > > >  /* The types that we are processing.  */
> > > >  #define TRAIT_EXPR_TYPE1(NODE) \
> > > >    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> > > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > > index 64bcfb18196..16a82a12a02 100644
> > > > --- a/gcc/cp/lex.cc
> > > > +++ b/gcc/cp/lex.cc
> > > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> > > >  #include "langhooks.h"
> > > >
> > > >  static int interface_strcmp (const char *);
> > > > +static void init_cp_traits (void);
> > > >  static void init_cp_pragma (void);
> > > >
> > > >  static tree parse_strconst_pragma (const char *, int);
> > > > @@ -283,6 +284,25 @@ init_reswords (void)
> > > >      }
> > > >  }
> > > >
> > > > +/* Initialize the C++ traits.  */
> > > > +static void
> > > > +init_cp_traits (void)
> > > > +{
> > > > +  tree id;
> > > > +
> > > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > +  id = get_identifier (NAME); \
> > > > +  IDENTIFIER_CP_INDEX (id) = CPTK_##CODE; \
> > > > +  set_identifier_kind (id, cik_trait);
> > > > +#include "cp/cp-trait.def"
> > > > +#undef DEFTRAIT
> > >
> > > ... we could replace this straight-line code with a loop over cp_traits?
> > > It'd make cp_traits bigger but init_cp_traits should get much smaller,
> > > which should be a net win in terms of binary size.
> > >
> >
> > I see. Since we know the number of iterations would be up to 255 and
> > the inner statements are only 3 and pretty simple/small, I think it is
> > likely that we will benefit from loop unrolling. But do we want to
> > prioritize the binary size over the possible performance improvements?
>
> That's something I'd let the compiler decide on since it has a
> target-specific understanding of such tradeoffs :) And by writing it as
> a loop the compiler is free to unroll it if it decides doing so is
> worthwhile, whereas the other way around is not really possible here.
> So from that perspective it seems using a loop is the better default
> choice.
>

That makes sense, and I agree. Will add this change as well :)

> >
> > > > +
> > > > +  /* An alias for __is_same.  */
> > > > +  id = get_identifier ("__is_same_as");
> > > > +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> > > > +  set_identifier_kind (id, cik_trait);
> > > > +}
> > > > +
> > > >  static void
> > > >  init_cp_pragma (void)
> > > >  {
> > > > @@ -324,6 +344,7 @@ cxx_init (void)
> > > >    input_location = BUILTINS_LOCATION;
> > > >
> > > >    init_reswords ();
> > > > +  init_cp_traits ();
> > > >    init_tree ();
> > > >    init_cp_semantics ();
> > > >    init_operators ();
> > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > > index f3abae716fe..eba5272be03 100644
> > > > --- a/gcc/cp/parser.cc
> > > > +++ b/gcc/cp/parser.cc
> > > > @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
> > > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > >  static void cp_lexer_stop_debugging
> > > >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > > > +static const cp_trait *cp_lexer_lookup_trait
> > > > +  (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > > +  (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > > +  (const cp_token *);
> > > >
> > > >  static cp_token_cache *cp_token_cache_new
> > > >    (cp_token *, cp_token *);
> > > > @@ -279,6 +285,19 @@ static FILE *cp_lexer_debug_stream;
> > > >     sizeof, typeof, or alignof.  */
> > > >  int cp_unevaluated_operand;
> > > >
> > > > +/* The trait table, declared in cp-tree.h.  */
> > > > +const cp_trait cp_traits[] =
> > > > +{
> > > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > +  { ARITY, CPTK_##CODE, (TCC == tcc_type) },
> > > > +#include "cp-trait.def"
> > > > +#undef DEFTRAIT
> > > > +};
> > > > +/* The trait table cannot have more than 255 (addr_space_t) entries since
> > > > +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> > > > +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> > > > +              "cp_traits array cannot have more than 255 entries");
> > > > +
> > > >  /* Dump up to NUM tokens in BUFFER to FILE starting with token
> > > >     START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
> > > >     first token in BUFFER.  If NUM is 0, dump all the tokens.  If
> > > > @@ -1167,12 +1186,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > >      case RID_CONSTEVAL:
> > > >        return true;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > -      return true;
> > > > -
> > > >      default:
> > > >        if (keyword >= RID_FIRST_INT_N
> > > >         && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > > @@ -1182,6 +1195,48 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > >      }
> > > >  }
> > > >
> > > > +/* Look ups the corresponding built-in trait if a given token is
> > > > +   a built-in trait.  Otherwise, returns nullptr.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait (const cp_token *token)
> > > > +{
> > > > +  tree id = token->u.value;
> > > > +
> > > > +  if (token->type == CPP_NAME
> > > > +      && TREE_CODE (id) == IDENTIFIER_NODE
> > >
> > > The value of a CPP_NAME token is always an IDENTIFIER_NODE, so this
> > > check should be redundant.  Also we should access the u.value union member
> > > only after the CPP_NAME check, since for some other token kinds u.value
> > > isn't the active member (and reading from it would be undefined behavior
> > > strictly speaking).
> > >
> >
> > Thank you!
> >
> > > > +      && IDENTIFIER_TRAIT_P (id))
> > > > +    return &cp_traits[IDENTIFIER_CP_INDEX (id)];
> > > > +
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is an expression-yielding
> > > > +   built-in trait.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > > +{
> > > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > +  if (trait && !trait->type)
> > > > +    return trait;
> > > > +
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is a type-yielding
> > > > +   built-in trait.  */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > > +{
> > > > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > +  if (trait && trait->type)
> > > > +    return trait;
> > > > +
> > > > +  return nullptr;
> > > > +}
> > > > +
> > > >  /* Return true if the next token is a keyword for a decl-specifier.  */
> > > >
> > > >  static bool
> > > > @@ -1190,6 +1245,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > > >    cp_token *token;
> > > >
> > > >    token = cp_lexer_peek_token (lexer);
> > > > +  if (cp_lexer_lookup_trait_type (token))
> > > > +    return true;
> > > >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> > > >  }
> > > >
> > > > @@ -2854,7 +2911,7 @@ static void cp_parser_late_parsing_default_args
> > > >  static tree cp_parser_sizeof_operand
> > > >    (cp_parser *, enum rid);
> > > >  static cp_expr cp_parser_trait
> > > > -  (cp_parser *, enum rid);
> > > > +  (cp_parser *, const cp_trait *);
> > > >  static bool cp_parser_declares_only_class_p
> > > >    (cp_parser *);
> > > >  static void cp_parser_set_storage_class
> > > > @@ -6021,12 +6078,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > > >       case RID_OFFSETOF:
> > > >         return cp_parser_builtin_offsetof (parser);
> > > >
> > > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > > -     case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_EXPR
> > > > -       return cp_parser_trait (parser, token->keyword);
> > > > -
> > > >       // C++ concepts
> > > >       case RID_REQUIRES:
> > > >         return cp_parser_requires_expression (parser);
> > > > @@ -6065,6 +6116,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > > >        `::' as the beginning of a qualified-id, or the "operator"
> > > >        keyword.  */
> > > >      case CPP_NAME:
> > > > +      {
> > > > +     const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > > +     if (trait)
> > >
> > > A tiny nit, but we could remove the extra block scope here by doing
> > > 'if (const cp_trait* trait = ...)' instead.
> > >
> >
> > Thank you!
> >
> > > > +       return cp_parser_trait (parser, trait);
> > > > +      }
> > > > +      /* FALLTHRU */
> > > >      case CPP_SCOPE:
> > > >      case CPP_TEMPLATE_ID:
> > > >      case CPP_NESTED_NAME_SPECIFIER:
> > > > @@ -11033,28 +11090,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > > >  /* Parse a builtin trait expression or type.  */
> > > >
> > > >  static cp_expr
> > > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > > >  {
> > > > -  cp_trait_kind kind;
> > > >    tree type1, type2 = NULL_TREE;
> > > > -  bool binary = false;
> > > > -  bool variadic = false;
> > > > -  bool type = false;
> > > > -
> > > > -  switch (keyword)
> > > > -    {
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:                  \
> > > > -      kind = CPTK_##CODE;             \
> > > > -      binary = (ARITY == 2);          \
> > > > -      variadic = (ARITY == -1);               \
> > > > -      type = (TCC == tcc_type);               \
> > > > -      break;
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -    default:
> > > > -      gcc_unreachable ();
> > > > -    }
> > > > +  const bool binary = (trait->arity == 2);
> > > > +  const bool variadic = (trait->arity == -1);
> > >
> > > Could we continue defining the local variables 'kind' and 'type' here so
> > > that we don't have to adjust their uses in the rest of the function?
> > > That should yield a smaller diff for this function.
> > >
> >
> > Yes, I will update this patch. Thank you!
> >
> > > >
> > > >    /* Get location of initial token.  */
> > > >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > @@ -11063,12 +11103,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >    cp_lexer_consume_token (parser->lexer);
> > > >
> > > >    matching_parens parens;
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      cp_parser_require (parser, CPP_LESS, RT_LESS);
> > > >    else
> > > >      parens.require_open (parser);
> > > >
> > > > -  if (kind == CPTK_IS_DEDUCIBLE)
> > > > +  if (trait->kind == CPTK_IS_DEDUCIBLE)
> > > >      {
> > > >        const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > > >        type1 = cp_parser_id_expression (parser,
> > > > @@ -11079,7 +11119,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >                                      /*optional_p=*/false);
> > > >        type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > > >      }
> > > > -  else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      /* __type_pack_element takes an expression as its first argument and uses
> > > >         template-id syntax instead of function call syntax (for consistency
> > > >         with Clang).  We special case these properties of __type_pack_element
> > > > @@ -11094,7 +11134,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >    if (type1 == error_mark_node)
> > > >      return error_mark_node;
> > > >
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      {
> > > >        cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > > >        tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > > @@ -11144,7 +11184,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >      }
> > > >
> > > >    location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > -  if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > +  if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > >      /* cp_parser_enclosed_template_argument_list above already took care
> > > >         of parsing the closing '>'.  */;
> > > >    else
> > > > @@ -11158,17 +11198,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >
> > > >    /* Complete the trait expression, which may mean either processing
> > > >       the trait expr now or saving it for template instantiation.  */
> > > > -  switch (kind)
> > > > +  switch (trait->kind)
> > > >      {
> > > >      case CPTK_BASES:
> > > >        return cp_expr (finish_bases (type1, false), trait_loc);
> > > >      case CPTK_DIRECT_BASES:
> > > >        return cp_expr (finish_bases (type1, true), trait_loc);
> > > >      default:
> > > > -      if (type)
> > > > -     return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > > +      if (trait->type)
> > > > +     return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > > >        else
> > > > -     return finish_trait_expr (trait_loc, kind, type1, type2);
> > > > +     return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > > >      }
> > > >  }
> > > >
> > > > @@ -20081,20 +20121,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > > >
> > > >        return type;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > -    case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > -      type = cp_parser_trait (parser, token->keyword);
> > > > +    default:
> > > > +      break;
> > > > +    }
> > > > +
> > > > +  /* If token is a type-yielding built-in traits, parse it.  */
> > > > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > > +  if (trait)
> > > > +    {
> > > > +      type = cp_parser_trait (parser, trait);
> > > >        if (decl_specs)
> > > >       cp_parser_set_decl_spec_type (decl_specs, type,
> > > >                                     token,
> > > >                                     /*type_definition_p=*/false);
> > > >
> > > >        return type;
> > > > -
> > > > -    default:
> > > > -      break;
> > > >      }
> > > >
> > > >    /* If token is an already-parsed decltype not followed by ::,
> > > > --
> > > > 2.42.0
> > > >
> > > >
> > >
> >
> >

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v20 01/40] c++: Sort built-in traits alphabetically
  2023-10-16 21:12                       ` Patrick Palka
@ 2023-10-16 21:30                         ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-16 21:30 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 16, 2023 at 2:12 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Mon, 16 Oct 2023, Ken Matsui wrote:
>
> > On Mon, Oct 16, 2023 at 8:17 AM Patrick Palka <ppalka@redhat.com> wrote:
> > >
> > > On Sun, 15 Oct 2023, Ken Matsui wrote:
> > >
> > > > This patch sorts built-in traits alphabetically for better code
> > > > readability.
> > >
> > > Hmm, I'm not sure if we still want/need this change with this current
> > > approach.  IIUC gperf would sort the trait names when generating the
> > > hash table code, and so we wanted a more consistent mapping from the
> > > cp-trait.def file to the generated code.  But with this current
> > > non-gperf approach I'm inclined to leave the existing ordering alone
> > > for sake of simplicity, and I kind of like that in cp-trait.def we
> > > currently group all expression-yielding traits together and all
> > > type-yielding traits together; that seems like a more natural layout
> > > than plain alphabetical sorting.
> > >
> >
> > I see. But this patch is crucial for me to keep all my existing
> > patches almost conflict-free against rebase, including drop, add, and
> > edit like you suggested to split integral-related patches. Without
> > this patch and alphabetical order, I will need to put a new trait in a
> > random place not close to surrounding commits, as Git relates close
> > lines when it finds conflicts. When I merged all my patches into one
> > patch series, I needed to fix conflicts for all my patches almost
> > every time I rebased. Both thinking of the random place and fixing the
> > conflicts of all patches would definitely not be desirable. Would you
> > think we should drop this patch?
>
> Fair enough, I'm all for keeping this patch and alphabetizing then :)
>

Thank you!

> >
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > >       * constraint.cc (diagnose_trait_expr): Sort built-in traits
> > > >       alphabetically.
> > > >       * cp-trait.def: Likewise.
> > > >       * semantics.cc (trait_expr_value): Likewise.
> > > >       (finish_trait_expr): Likewise.
> > > >       (finish_trait_type): Likewise.
> > > >
> > > > gcc/testsuite/ChangeLog:
> > > >
> > > >       * g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.
> > > >
> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > > ---
> > > >  gcc/cp/constraint.cc                     | 68 ++++++++---------
> > > >  gcc/cp/cp-trait.def                      | 10 +--
> > > >  gcc/cp/semantics.cc                      | 94 ++++++++++++------------
> > > >  gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
> > > >  4 files changed, 121 insertions(+), 121 deletions(-)
> > > >
> > > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > > index c9e4e7043cd..722fc334e6f 100644
> > > > --- a/gcc/cp/constraint.cc
> > > > +++ b/gcc/cp/constraint.cc
> > > > @@ -3702,18 +3702,36 @@ diagnose_trait_expr (tree expr, tree args)
> > > >      case CPTK_HAS_TRIVIAL_DESTRUCTOR:
> > > >        inform (loc, "  %qT is not trivially destructible", t1);
> > > >        break;
> > > > +    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > > +      inform (loc, "  %qT does not have unique object representations", t1);
> > > > +      break;
> > > >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > >        inform (loc, "  %qT does not have a virtual destructor", t1);
> > > >        break;
> > > >      case CPTK_IS_ABSTRACT:
> > > >        inform (loc, "  %qT is not an abstract class", t1);
> > > >        break;
> > > > +    case CPTK_IS_AGGREGATE:
> > > > +      inform (loc, "  %qT is not an aggregate", t1);
> > > > +      break;
> > > > +    case CPTK_IS_ASSIGNABLE:
> > > > +      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > > > +      break;
> > > >      case CPTK_IS_BASE_OF:
> > > >        inform (loc, "  %qT is not a base of %qT", t1, t2);
> > > >        break;
> > > >      case CPTK_IS_CLASS:
> > > >        inform (loc, "  %qT is not a class", t1);
> > > >        break;
> > > > +    case CPTK_IS_CONSTRUCTIBLE:
> > > > +      if (!t2)
> > > > +    inform (loc, "  %qT is not default constructible", t1);
> > > > +      else
> > > > +    inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > > > +      break;
> > > > +    case CPTK_IS_CONVERTIBLE:
> > > > +      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > > > +      break;
> > > >      case CPTK_IS_EMPTY:
> > > >        inform (loc, "  %qT is not an empty class", t1);
> > > >        break;
> > > > @@ -3729,6 +3747,18 @@ diagnose_trait_expr (tree expr, tree args)
> > > >      case CPTK_IS_LITERAL_TYPE:
> > > >        inform (loc, "  %qT is not a literal type", t1);
> > > >        break;
> > > > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > > +      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > > > +      break;
> > > > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > > +      if (!t2)
> > > > +     inform (loc, "  %qT is not nothrow default constructible", t1);
> > > > +      else
> > > > +     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > > > +      break;
> > > > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > > +       inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > > > +      break;
> > > >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> > > >        inform (loc, "  %qT is not pointer-interconvertible base of %qT",
> > > >             t1, t2);
> > > > @@ -3748,50 +3778,20 @@ diagnose_trait_expr (tree expr, tree args)
> > > >      case CPTK_IS_TRIVIAL:
> > > >        inform (loc, "  %qT is not a trivial type", t1);
> > > >        break;
> > > > -    case CPTK_IS_UNION:
> > > > -      inform (loc, "  %qT is not a union", t1);
> > > > -      break;
> > > > -    case CPTK_IS_AGGREGATE:
> > > > -      inform (loc, "  %qT is not an aggregate", t1);
> > > > -      break;
> > > > -    case CPTK_IS_TRIVIALLY_COPYABLE:
> > > > -      inform (loc, "  %qT is not trivially copyable", t1);
> > > > -      break;
> > > > -    case CPTK_IS_ASSIGNABLE:
> > > > -      inform (loc, "  %qT is not assignable from %qT", t1, t2);
> > > > -      break;
> > > >      case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > > >        inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
> > > >        break;
> > > > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > > -      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
> > > > -      break;
> > > > -    case CPTK_IS_CONSTRUCTIBLE:
> > > > -      if (!t2)
> > > > -     inform (loc, "  %qT is not default constructible", t1);
> > > > -      else
> > > > -     inform (loc, "  %qT is not constructible from %qE", t1, t2);
> > > > -      break;
> > > >      case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > > >        if (!t2)
> > > >       inform (loc, "  %qT is not trivially default constructible", t1);
> > > >        else
> > > >       inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
> > > >        break;
> > > > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > > -      if (!t2)
> > > > -     inform (loc, "  %qT is not nothrow default constructible", t1);
> > > > -      else
> > > > -     inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
> > > > -      break;
> > > > -    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > > -      inform (loc, "  %qT does not have unique object representations", t1);
> > > > -      break;
> > > > -    case CPTK_IS_CONVERTIBLE:
> > > > -      inform (loc, "  %qT is not convertible from %qE", t2, t1);
> > > > +    case CPTK_IS_TRIVIALLY_COPYABLE:
> > > > +      inform (loc, "  %qT is not trivially copyable", t1);
> > > >        break;
> > > > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > > -     inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
> > > > +    case CPTK_IS_UNION:
> > > > +      inform (loc, "  %qT is not a union", t1);
> > > >        break;
> > > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > > >        inform (loc, "  %qT is not a reference that binds to a temporary "
> > > > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > > > index 8b7fece0cc8..0e48e64b8dd 100644
> > > > --- a/gcc/cp/cp-trait.def
> > > > +++ b/gcc/cp/cp-trait.def
> > > > @@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
> > > >  DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
> > > > -DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> > > > -
> > > >  DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
> > > > -DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> > > >  DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
> > > > -DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
> > > > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
> > > >  DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
> > > > +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
> > > > +
> > > > +/* FIXME Added space to avoid direct usage in GCC 13.  */
> > > > +DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
> > > >
> > > >  /* These traits yield a type pack, not a type, and are represented by
> > > >     cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
> > > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > > > index 80ef1364e33..782aa515da0 100644
> > > > --- a/gcc/cp/semantics.cc
> > > > +++ b/gcc/cp/semantics.cc
> > > > @@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >                     && classtype_has_nothrow_assign_or_copy_p (type1,
> > > >                                                                true))));
> > > >
> > > > -    case CPTK_HAS_TRIVIAL_ASSIGN:
> > > > -      /* ??? The standard seems to be missing the "or array of such a class
> > > > -      type" wording for this trait.  */
> > > > -      type1 = strip_array_types (type1);
> > > > -      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > > > -           && (trivial_type_p (type1)
> > > > -                 || (CLASS_TYPE_P (type1)
> > > > -                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > > > -
> > > >      case CPTK_HAS_NOTHROW_CONSTRUCTOR:
> > > >        type1 = strip_array_types (type1);
> > > >        return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
> > > > @@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >                 && maybe_instantiate_noexcept (t)
> > > >                 && TYPE_NOTHROW_P (TREE_TYPE (t))));
> > > >
> > > > -    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > > > -      type1 = strip_array_types (type1);
> > > > -      return (trivial_type_p (type1)
> > > > -           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > > > -
> > > >      case CPTK_HAS_NOTHROW_COPY:
> > > >        type1 = strip_array_types (type1);
> > > >        return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
> > > >             || (CLASS_TYPE_P (type1)
> > > >                 && classtype_has_nothrow_assign_or_copy_p (type1, false)));
> > > >
> > > > +    case CPTK_HAS_TRIVIAL_ASSIGN:
> > > > +      /* ??? The standard seems to be missing the "or array of such a class
> > > > +      type" wording for this trait.  */
> > > > +      type1 = strip_array_types (type1);
> > > > +      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
> > > > +           && (trivial_type_p (type1)
> > > > +                 || (CLASS_TYPE_P (type1)
> > > > +                     && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
> > > > +
> > > > +    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
> > > > +      type1 = strip_array_types (type1);
> > > > +      return (trivial_type_p (type1)
> > > > +           || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
> > > > +
> > > >      case CPTK_HAS_TRIVIAL_COPY:
> > > >        /* ??? The standard seems to be missing the "or array of such a class
> > > >        type" wording for this trait.  */
> > > > @@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >             || (CLASS_TYPE_P (type1)
> > > >                 && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
> > > >
> > > > -    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > > -      return type_has_virtual_destructor (type1);
> > > > -
> > > >      case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
> > > >        return type_has_unique_obj_representations (type1);
> > > >
> > > > +    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > > +      return type_has_virtual_destructor (type1);
> > > > +
> > > >      case CPTK_IS_ABSTRACT:
> > > >        return ABSTRACT_CLASS_TYPE_P (type1);
> > > >
> > > >      case CPTK_IS_AGGREGATE:
> > > >        return CP_AGGREGATE_TYPE_P (type1);
> > > >
> > > > +    case CPTK_IS_ASSIGNABLE:
> > > > +      return is_xible (MODIFY_EXPR, type1, type2);
> > > > +
> > > >      case CPTK_IS_BASE_OF:
> > > >        return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
> > > >             && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
> > > > @@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >      case CPTK_IS_CLASS:
> > > >        return NON_UNION_CLASS_TYPE_P (type1);
> > > >
> > > > +    case CPTK_IS_CONSTRUCTIBLE:
> > > > +      return is_xible (INIT_EXPR, type1, type2);
> > > > +
> > > > +    case CPTK_IS_CONVERTIBLE:
> > > > +      return is_convertible (type1, type2);
> > > > +
> > > >      case CPTK_IS_EMPTY:
> > > >        return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
> > > >
> > > > @@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >      case CPTK_IS_LITERAL_TYPE:
> > > >        return literal_type_p (type1);
> > > >
> > > > +    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > > +      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > > > +
> > > > +    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > > +      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > > > +
> > > > +    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > > +      return is_nothrow_convertible (type1, type2);
> > > > +
> > > >      case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
> > > >        return pointer_interconvertible_base_of_p (type1, type2);
> > > >
> > > > @@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > > >      case CPTK_IS_UNION:
> > > >        return type_code1 == UNION_TYPE;
> > > >
> > > > -    case CPTK_IS_ASSIGNABLE:
> > > > -      return is_xible (MODIFY_EXPR, type1, type2);
> > > > -
> > > > -    case CPTK_IS_CONSTRUCTIBLE:
> > > > -      return is_xible (INIT_EXPR, type1, type2);
> > > > -
> > > > -    case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > > -      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
> > > > -
> > > > -    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > > -      return is_nothrow_xible (INIT_EXPR, type1, type2);
> > > > -
> > > > -    case CPTK_IS_CONVERTIBLE:
> > > > -      return is_convertible (type1, type2);
> > > > -
> > > > -    case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > > -      return is_nothrow_convertible (type1, type2);
> > > > -
> > > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > > >        return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
> > > >
> > > > @@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > > >       return error_mark_node;
> > > >        break;
> > > >
> > > > +    case CPTK_IS_ABSTRACT:
> > > >      case CPTK_IS_EMPTY:
> > > >      case CPTK_IS_POLYMORPHIC:
> > > > -    case CPTK_IS_ABSTRACT:
> > > >      case CPTK_HAS_VIRTUAL_DESTRUCTOR:
> > > >        if (!check_trait_type (type1, /* kind = */ 3))
> > > >       return error_mark_node;
> > > > @@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > > >       return error_mark_node;
> > > >        break;
> > > >
> > > > -    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > > > -    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > > > +    case CPTK_IS_CONVERTIBLE:
> > > >      case CPTK_IS_NOTHROW_ASSIGNABLE:
> > > >      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > > > -    case CPTK_IS_CONVERTIBLE:
> > > >      case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > > +    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
> > > > +    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
> > > >      case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
> > > >      case CPTK_REF_CONVERTS_FROM_TEMPORARY:
> > > >        if (!check_trait_type (type1)
> > > > @@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > > >
> > > >      case CPTK_IS_CLASS:
> > > >      case CPTK_IS_ENUM:
> > > > -    case CPTK_IS_UNION:
> > > >      case CPTK_IS_SAME:
> > > > +    case CPTK_IS_UNION:
> > > >        break;
> > > >
> > > >      case CPTK_IS_LAYOUT_COMPATIBLE:
> > > > @@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
> > > >
> > > >    switch (kind)
> > > >      {
> > > > -    case CPTK_UNDERLYING_TYPE:
> > > > -      return finish_underlying_type (type1);
> > > > -
> > > >      case CPTK_REMOVE_CV:
> > > >        return cv_unqualified (type1);
> > > >
> > > > -    case CPTK_REMOVE_REFERENCE:
> > > > +    case CPTK_REMOVE_CVREF:
> > > >        if (TYPE_REF_P (type1))
> > > >       type1 = TREE_TYPE (type1);
> > > > -      return type1;
> > > > +      return cv_unqualified (type1);
> > > >
> > > > -    case CPTK_REMOVE_CVREF:
> > > > +    case CPTK_REMOVE_REFERENCE:
> > > >        if (TYPE_REF_P (type1))
> > > >       type1 = TREE_TYPE (type1);
> > > > -      return cv_unqualified (type1);
> > > > +      return type1;
> > > >
> > > >      case CPTK_TYPE_PACK_ELEMENT:
> > > >        return finish_type_pack_element (type1, type2, complain);
> > > >
> > > > +    case CPTK_UNDERLYING_TYPE:
> > > > +      return finish_underlying_type (type1);
> > > > +
> > > >  #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > >      case CPTK_##CODE:
> > > >  #include "cp-trait.def"
> > > > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > > index f343e153e56..2223f08a628 100644
> > > > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > > @@ -8,9 +8,21 @@
> > > >  #if !__has_builtin (__builtin_bit_cast)
> > > >  # error "__has_builtin (__builtin_bit_cast) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__builtin_is_constant_evaluated)
> > > > +# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > > > +#endif
> > > > +#if !__has_builtin (__builtin_is_corresponding_member)
> > > > +# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > > > +#endif
> > > > +#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > > > +# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__builtin_launder)
> > > >  # error "__has_builtin (__builtin_launder) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__builtin_source_location)
> > > > +# error "__has_builtin (__builtin_source_location) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__has_nothrow_assign)
> > > >  # error "__has_builtin (__has_nothrow_assign) failed"
> > > >  #endif
> > > > @@ -44,12 +56,21 @@
> > > >  #if !__has_builtin (__is_aggregate)
> > > >  # error "__has_builtin (__is_aggregate) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__is_assignable)
> > > > +# error "__has_builtin (__is_assignable) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__is_base_of)
> > > >  # error "__has_builtin (__is_base_of) failed"
> > > >  #endif
> > > >  #if !__has_builtin (__is_class)
> > > >  # error "__has_builtin (__is_class) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__is_constructible)
> > > > +# error "__has_builtin (__is_constructible) failed"
> > > > +#endif
> > > > +#if !__has_builtin (__is_convertible)
> > > > +# error "__has_builtin (__is_convertible) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__is_empty)
> > > >  # error "__has_builtin (__is_empty) failed"
> > > >  #endif
> > > > @@ -65,6 +86,15 @@
> > > >  #if !__has_builtin (__is_literal_type)
> > > >  # error "__has_builtin (__is_literal_type) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__is_nothrow_assignable)
> > > > +# error "__has_builtin (__is_nothrow_assignable) failed"
> > > > +#endif
> > > > +#if !__has_builtin (__is_nothrow_constructible)
> > > > +# error "__has_builtin (__is_nothrow_constructible) failed"
> > > > +#endif
> > > > +#if !__has_builtin (__is_nothrow_convertible)
> > > > +# error "__has_builtin (__is_nothrow_convertible) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__is_pointer_interconvertible_base_of)
> > > >  # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
> > > >  #endif
> > > > @@ -98,51 +128,21 @@
> > > >  #if !__has_builtin (__is_union)
> > > >  # error "__has_builtin (__is_union) failed"
> > > >  #endif
> > > > -#if !__has_builtin (__underlying_type)
> > > > -# error "__has_builtin (__underlying_type) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_assignable)
> > > > -# error "__has_builtin (__is_assignable) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_constructible)
> > > > -# error "__has_builtin (__is_constructible) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_nothrow_assignable)
> > > > -# error "__has_builtin (__is_nothrow_assignable) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_nothrow_constructible)
> > > > -# error "__has_builtin (__is_nothrow_constructible) failed"
> > > > -#endif
> > > >  #if !__has_builtin (__reference_constructs_from_temporary)
> > > >  # error "__has_builtin (__reference_constructs_from_temporary) failed"
> > > >  #endif
> > > >  #if !__has_builtin (__reference_converts_from_temporary)
> > > >  # error "__has_builtin (__reference_converts_from_temporary) failed"
> > > >  #endif
> > > > -#if !__has_builtin (__builtin_is_constant_evaluated)
> > > > -# error "__has_builtin (__builtin_is_constant_evaluated) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__builtin_source_location)
> > > > -# error "__has_builtin (__builtin_source_location) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__builtin_is_corresponding_member)
> > > > -# error "__has_builtin (__builtin_is_corresponding_member) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
> > > > -# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_convertible)
> > > > -# error "__has_builtin (__is_convertible) failed"
> > > > -#endif
> > > > -#if !__has_builtin (__is_nothrow_convertible)
> > > > -# error "__has_builtin (__is_nothrow_convertible) failed"
> > > > -#endif
> > > >  #if !__has_builtin (__remove_cv)
> > > >  # error "__has_builtin (__remove_cv) failed"
> > > >  #endif
> > > > +#if !__has_builtin (__remove_cvref)
> > > > +# error "__has_builtin (__remove_cvref) failed"
> > > > +#endif
> > > >  #if !__has_builtin (__remove_reference)
> > > >  # error "__has_builtin (__remove_reference) failed"
> > > >  #endif
> > > > -#if !__has_builtin (__remove_cvref)
> > > > -# error "__has_builtin (__remove_cvref) failed"
> > > > +#if !__has_builtin (__underlying_type)
> > > > +# error "__has_builtin (__underlying_type) failed"
> > > >  #endif
> > > > --
> > > > 2.42.0
> > > >
> > > >
> > >
> >
> >

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 00/30] Optimize type traits performance
  2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
                                   ` (39 preceding siblings ...)
  2023-10-16  0:10                 ` [PATCH v20 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
@ 2023-10-17 11:27                 ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 01/30] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                     ` (30 more replies)
  40 siblings, 31 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.


Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (30):
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize std::is_const compilation performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize std::is_volatile compilation performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize std::is_unbounded_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize std::is_pointer compilation performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/constraint.cc			       |  39 ++++
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait.def			       |  14 ++
 gcc/cp/cp-tree.h			       |  33 ++-
 gcc/cp/lex.cc				       |  21 ++
 gcc/cp/parser.cc			       | 133 +++++++----
 gcc/cp/semantics.cc			       |  59 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      |  42 ++++
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 +++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 +++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 +++
 gcc/testsuite/g++.dg/ext/is_object.C	       |  29 +++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 +++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 207 +++++++++++++++++-
 26 files changed, 1021 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 01/30] c-family, c++: Look up built-in traits via identifier node
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 02/30] c++: Accept the use of built-in trait identifiers Ken Matsui
                                     ` (29 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses the identifier node to look up the specific trait.  Rather
than holding traits as keywords, we set all trait identifiers as cik_trait,
which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(num_cp_traits): New variable to hold the size of cp_traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (init_cp_traits): New function to set cik_trait and
	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_traits): Define its values, declared in cp-tree.h.
	(num_cp_traits): Define its value, declared in cp-tree.h.
	(cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 ---
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  33 ++++++++---
 gcc/cp/lex.cc             |  21 +++++++
 gcc/cp/parser.cc          | 120 +++++++++++++++++++++++++-------------
 6 files changed, 129 insertions(+), 65 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index efcd2de54e5..81a5c06a574 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1375,16 +1381,27 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  const char *name;
+  cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+
+/* The trait table.  */
+extern const struct cp_trait cp_traits[];
+extern const addr_space_t num_cp_traits;
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..872ca970545 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+  for (unsigned int i = 0; i < num_cp_traits; ++i)
+    {
+      id = get_identifier (cp_traits[i].name);
+      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
+      set_identifier_kind (id, cik_trait);
+    }
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +344,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 59b9852895e..ece238c2072 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -279,6 +285,21 @@ static FILE *cp_lexer_debug_stream;
    sizeof, typeof, or alignof.  */
 int cp_unevaluated_operand;
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+const addr_space_t num_cp_traits = ARRAY_SIZE (cp_traits);
+
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(num_cp_traits <= 255,
+              "cp_traits array cannot have more than 255 entries");
+
 /* Dump up to NUM tokens in BUFFER to FILE starting with token
    START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
    first token in BUFFER.  If NUM is 0, dump all the tokens.  If
@@ -1167,12 +1188,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1197,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
+    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1243,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2909,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6029,12 +6084,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6073,6 +6122,9 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+	return cp_parser_trait (parser, trait);
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11041,28 +11093,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
+  const cp_trait_kind kind = trait->kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
+  const bool type = trait->type;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -20089,20 +20126,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 02/30] c++: Accept the use of built-in trait identifiers
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 01/30] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 03/30] c++: Implement __is_const built-in trait Ken Matsui
                                     ` (28 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 47 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ece238c2072..e4c45190313 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1197,15 +1197,27 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1213,9 +1225,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1226,9 +1238,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1243,7 +1255,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6122,7 +6134,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait
+	  = cp_lexer_peek_trait_expr (parser->lexer, token))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20131,7 +20144,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 03/30] c++: Implement __is_const built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 01/30] c-family, c++: Look up built-in traits via identifier node Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 02/30] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 04/30] libstdc++: Optimize std::is_const compilation performance Ken Matsui
                                     ` (27 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41fe2812ac4..41d9eef7227 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 144cb440fa3..7fbcfd7ccad 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 04/30] libstdc++: Optimize std::is_const compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (2 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 03/30] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 05/30] c++: Implement __is_volatile built-in trait Ken Matsui
                                     ` (26 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_const
by dispatching to the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 05/30] c++: Implement __is_volatile built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (3 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 04/30] libstdc++: Optimize std::is_const compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 06/30] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
                                     ` (25 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41d9eef7227..54782a167dd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7fbcfd7ccad..7726fa99711 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 06/30] libstdc++: Optimize std::is_volatile compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (4 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 05/30] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 07/30] c++: Implement __is_array built-in trait Ken Matsui
                                     ` (24 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_volatile
by dispatching to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 07/30] c++: Implement __is_array built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (5 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 06/30] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 08/30] libstdc++: Optimize std::is_array compilation performance Ken Matsui
                                     ` (23 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 54782a167dd..b9f89fe178c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3715,6 +3715,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7726fa99711..8d5874d6ab0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 08/30] libstdc++: Optimize std::is_array compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (6 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 07/30] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 09/30] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                     ` (22 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_array
by dispatching to the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 09/30] c++: Implement __is_unbounded_array built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (7 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 08/30] libstdc++: Optimize std::is_array compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 10/30] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
                                     ` (21 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b9f89fe178c..292b941e6a0 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5874d6ab0..bd73323e6db 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 10/30] libstdc++: Optimize std::is_unbounded_array compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (8 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 09/30] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 11/30] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                     ` (20 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_unbounded_array
by dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 11/30] c++: Implement __is_bounded_array built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (9 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 10/30] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 12/30] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
                                     ` (19 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 292b941e6a0..71a40558881 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bd73323e6db..aab35c9e5ba 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 12/30] libstdc++: Optimize std::is_bounded_array compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (10 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 11/30] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 13/30] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                     ` (18 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_bounded_array
by dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 13/30] c++: Implement __is_scoped_enum built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (11 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 12/30] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 14/30] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
                                     ` (17 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 71a40558881..2b46e3afa97 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3782,6 +3782,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index aab35c9e5ba..9f0e468f489 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 14/30] libstdc++: Optimize std::is_scoped_enum compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (12 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 13/30] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 15/30] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                     ` (16 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_scoped_enum
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 15/30] c++: Implement __is_member_pointer built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (13 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 14/30] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 16/30] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
                                     ` (15 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2b46e3afa97..a969a069db4 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9f0e468f489..5ca05dde75d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 16/30] libstdc++: Optimize std::is_member_pointer compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (14 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 15/30] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 17/30] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                     ` (14 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_member_pointer
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 17/30] c++: Implement __is_member_function_pointer built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (15 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 16/30] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 18/30] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
                                     ` (13 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a969a069db4..dde83533382 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5ca05dde75d..59aaa256232 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 18/30] libstdc++: Optimize std::is_member_function_pointer compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (16 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 17/30] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 19/30] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                     ` (12 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_function_pointer by dispatching to the new
__is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 19/30] c++: Implement __is_member_object_pointer built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (17 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 18/30] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 20/30] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
                                     ` (11 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index dde83533382..9db3a60943e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3760,6 +3760,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 59aaa256232..c7e6396370d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 20/30] libstdc++: Optimize std::is_member_object_pointer compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (18 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 19/30] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 21/30] c++: Implement __is_reference built-in trait Ken Matsui
                                     ` (10 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_object_pointer by dispatching to the new
__is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 21/30] c++: Implement __is_reference built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (19 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 20/30] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 22/30] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
                                     ` (9 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9db3a60943e..e05d4fa4d20 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3788,6 +3788,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c7e6396370d..cd17cd176cb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 22/30] libstdc++: Optimize std::is_reference compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (20 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 21/30] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 23/30] c++: Implement __is_function built-in trait Ken Matsui
                                     ` (8 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_reference
by dispatching to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 23/30] c++: Implement __is_function built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (21 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 22/30] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 24/30] libstdc++: Optimize std::is_function compilation performance Ken Matsui
                                     ` (7 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index e05d4fa4d20..c394657d6b9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3751,6 +3751,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cd17cd176cb..8118d3104c7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 24/30] libstdc++: Optimize std::is_function compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (22 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 23/30] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 25/30] c++: Implement __is_object built-in trait Ken Matsui
                                     ` (6 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_function
by dispatching to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 25/30] c++: Implement __is_object built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (23 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 24/30] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 26/30] libstdc++: Optimize std::is_object compilation performance Ken Matsui
                                     ` (5 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_object.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_object.
	* g++.dg/ext/is_object.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 +++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/semantics.cc                      |  6 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
 gcc/testsuite/g++.dg/ext/is_object.C     | 29 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c394657d6b9..444dbaacd78 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
 	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
+    case CPTK_IS_OBJECT:
+      inform (loc, "  %qT is not an object type", t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..191a86307fc 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8118d3104c7..e3f71ff5902 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
       return is_nothrow_convertible (type1, type2);
 
+    case CPTK_IS_OBJECT:
+      return (type_code1 != FUNCTION_TYPE
+	      && type_code1 != REFERENCE_TYPE
+	      && type_code1 != VOID_TYPE);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12412,6 +12417,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_OBJECT:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..163be1d710b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -116,6 +116,9 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__is_object)
+# error "__has_builtin (__is_object) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_object.C b/gcc/testsuite/g++.dg/ext/is_object.C
new file mode 100644
index 00000000000..5c759a5ef69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_object.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);				\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_NON_VOLATILE(__is_object, int (int), false);
+SA_TEST_NON_VOLATILE(__is_object, ClassType (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_object,
+		     float (int, float, int[], int&), false);
+SA_TEST_CATEGORY(__is_object, int&, false);
+SA_TEST_CATEGORY(__is_object, ClassType&, false);
+SA_TEST_NON_VOLATILE(__is_object, int(&)(int), false);
+SA_TEST_CATEGORY(__is_object, void, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_object, ClassType, true);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 26/30] libstdc++: Optimize std::is_object compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (24 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 25/30] c++: Implement __is_object built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 27/30] c++: Implement __remove_pointer built-in trait Ken Matsui
                                     ` (4 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_object
by dispatching to the new __is_object built-in trait.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_object built-in trait.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..a12a35c209b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<__is_object(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3312,15 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+template <typename _Tp>
+  inline constexpr bool is_object_v = __is_object(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 27/30] c++: Implement __remove_pointer built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (25 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 26/30] libstdc++: Optimize std::is_object compilation performance Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:27                   ` [PATCH v21 28/30] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
                                     ` (3 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 191a86307fc..1f405f61861 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -98,6 +98,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e3f71ff5902..45584e9045f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12494,6 +12494,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 163be1d710b..719902d3f1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -176,6 +176,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 28/30] libstdc++: Optimize std::remove_pointer compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (26 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 27/30] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-17 11:27                   ` Ken Matsui
  2023-10-17 11:28                   ` [PATCH v21 29/30] c++: Implement __is_pointer built-in trait Ken Matsui
                                     ` (2 subsequent siblings)
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::remove_pointer
by dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index a12a35c209b..50210297121 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2103,6 +2103,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2111,11 +2117,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 29/30] c++: Implement __is_pointer built-in trait
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (27 preceding siblings ...)
  2023-10-17 11:27                   ` [PATCH v21 28/30] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
@ 2023-10-17 11:28                   ` Ken Matsui
  2023-10-17 11:28                   ` [PATCH v21 30/30] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C    | 51 ++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 444dbaacd78..9fce36e12d1 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3791,6 +3791,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1f405f61861..05514a51c21 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45584e9045f..7cccbae5287 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12216,6 +12216,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12418,6 +12421,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_OBJECT:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 719902d3f1a..b1430e9bd8b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -125,6 +125,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v21 30/30] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (28 preceding siblings ...)
  2023-10-17 11:28                   ` [PATCH v21 29/30] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-17 11:28                   ` Ken Matsui
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
  30 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the compilation performance of std::is_pointer
by dispatching to the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..246f2cc0b17 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 50210297121..acd117cfa73 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 00/31] Optimize type traits performance
  2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
                                     ` (29 preceding siblings ...)
  2023-10-17 11:28                   ` [PATCH v21 30/30] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
@ 2023-10-17 11:36                   ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 01/31] c++: Sort built-in traits alphabetically Ken Matsui
                                       ` (31 more replies)
  30 siblings, 32 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (31):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize std::is_const compilation performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize std::is_volatile compilation performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize std::is_unbounded_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize std::is_pointer compilation performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/constraint.cc			       | 103 ++++++---
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait.def			       |  24 +-
 gcc/cp/cp-tree.h			       |  33 ++-
 gcc/cp/lex.cc				       |  21 ++
 gcc/cp/parser.cc			       | 133 +++++++----
 gcc/cp/semantics.cc			       | 149 +++++++++----
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 110 +++++++---
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 +++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 ++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 +++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 +++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 +++
 gcc/testsuite/g++.dg/ext/is_object.C	       |  29 +++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 +++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 207 +++++++++++++++++-
 26 files changed, 1137 insertions(+), 193 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 01/31] c++: Sort built-in traits alphabetically
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                       ` (30 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 64b64e17857..41fe2812ac4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3703,18 +3703,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3730,6 +3748,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3749,50 +3779,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 2a0cf963e91..144cb440fa3 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 01/31] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 17:04                       ` Patrick Palka
  2023-10-17 11:36                     ` [PATCH v22 03/31] c++: Accept the use of built-in trait identifiers Ken Matsui
                                       ` (29 subsequent siblings)
  31 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses the identifier node to look up the specific trait.  Rather
than holding traits as keywords, we set all trait identifiers as cik_trait,
which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(num_cp_traits): New variable to hold the size of cp_traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (init_cp_traits): New function to set cik_trait and
	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_traits): Define its values, declared in cp-tree.h.
	(num_cp_traits): Define its value, declared in cp-tree.h.
	(cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 ---
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  33 ++++++++---
 gcc/cp/lex.cc             |  21 +++++++
 gcc/cp/parser.cc          | 120 +++++++++++++++++++++++++-------------
 6 files changed, 129 insertions(+), 65 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index efcd2de54e5..81a5c06a574 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1375,16 +1381,27 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  const char *name;
+  cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+
+/* The trait table.  */
+extern const struct cp_trait cp_traits[];
+extern const addr_space_t num_cp_traits;
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..872ca970545 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+  for (unsigned int i = 0; i < num_cp_traits; ++i)
+    {
+      id = get_identifier (cp_traits[i].name);
+      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
+      set_identifier_kind (id, cik_trait);
+    }
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +344,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 59b9852895e..ece238c2072 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -279,6 +285,21 @@ static FILE *cp_lexer_debug_stream;
    sizeof, typeof, or alignof.  */
 int cp_unevaluated_operand;
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+const addr_space_t num_cp_traits = ARRAY_SIZE (cp_traits);
+
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(num_cp_traits <= 255,
+              "cp_traits array cannot have more than 255 entries");
+
 /* Dump up to NUM tokens in BUFFER to FILE starting with token
    START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
    first token in BUFFER.  If NUM is 0, dump all the tokens.  If
@@ -1167,12 +1188,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1197,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
+    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1243,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2909,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6029,12 +6084,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6073,6 +6122,9 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+	return cp_parser_trait (parser, trait);
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11041,28 +11093,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
+  const cp_trait_kind kind = trait->kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
+  const bool type = trait->type;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -20089,20 +20126,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 03/31] c++: Accept the use of built-in trait identifiers
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 01/31] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 04/31] c++: Implement __is_const built-in trait Ken Matsui
                                       ` (28 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 47 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ece238c2072..e4c45190313 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1197,15 +1197,27 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1213,9 +1225,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1226,9 +1238,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1243,7 +1255,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6122,7 +6134,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait
+	  = cp_lexer_peek_trait_expr (parser->lexer, token))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20131,7 +20144,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 04/31] c++: Implement __is_const built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (2 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 03/31] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 05/31] libstdc++: Optimize std::is_const compilation performance Ken Matsui
                                       ` (27 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41fe2812ac4..41d9eef7227 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 144cb440fa3..7fbcfd7ccad 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 05/31] libstdc++: Optimize std::is_const compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (3 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 04/31] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 06/31] c++: Implement __is_volatile built-in trait Ken Matsui
                                       ` (26 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_const
by dispatching to the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 06/31] c++: Implement __is_volatile built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (4 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 05/31] libstdc++: Optimize std::is_const compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 07/31] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
                                       ` (25 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41d9eef7227..54782a167dd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7fbcfd7ccad..7726fa99711 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 07/31] libstdc++: Optimize std::is_volatile compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (5 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 06/31] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 08/31] c++: Implement __is_array built-in trait Ken Matsui
                                       ` (24 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_volatile
by dispatching to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 08/31] c++: Implement __is_array built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (6 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 07/31] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 09/31] libstdc++: Optimize std::is_array compilation performance Ken Matsui
                                       ` (23 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 54782a167dd..b9f89fe178c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3715,6 +3715,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7726fa99711..8d5874d6ab0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 09/31] libstdc++: Optimize std::is_array compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (7 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 08/31] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 10/31] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                       ` (22 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_array
by dispatching to the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 10/31] c++: Implement __is_unbounded_array built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (8 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 09/31] libstdc++: Optimize std::is_array compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 11/31] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
                                       ` (21 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b9f89fe178c..292b941e6a0 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5874d6ab0..bd73323e6db 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 11/31] libstdc++: Optimize std::is_unbounded_array compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (9 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 10/31] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 12/31] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                       ` (20 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_unbounded_array
by dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 12/31] c++: Implement __is_bounded_array built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (10 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 11/31] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 13/31] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
                                       ` (19 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 292b941e6a0..71a40558881 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bd73323e6db..aab35c9e5ba 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 13/31] libstdc++: Optimize std::is_bounded_array compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (11 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 12/31] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 14/31] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                       ` (18 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_bounded_array
by dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 14/31] c++: Implement __is_scoped_enum built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (12 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 13/31] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 15/31] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
                                       ` (17 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 71a40558881..2b46e3afa97 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3782,6 +3782,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index aab35c9e5ba..9f0e468f489 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 15/31] libstdc++: Optimize std::is_scoped_enum compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (13 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 14/31] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 16/31] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                       ` (16 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_scoped_enum
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 16/31] c++: Implement __is_member_pointer built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (14 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 15/31] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 17/31] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
                                       ` (15 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2b46e3afa97..a969a069db4 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9f0e468f489..5ca05dde75d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 17/31] libstdc++: Optimize std::is_member_pointer compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (15 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 16/31] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 18/31] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                       ` (14 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_member_pointer
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 18/31] c++: Implement __is_member_function_pointer built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (16 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 17/31] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 19/31] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
                                       ` (13 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a969a069db4..dde83533382 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5ca05dde75d..59aaa256232 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 19/31] libstdc++: Optimize std::is_member_function_pointer compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (17 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 18/31] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 20/31] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                       ` (12 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_function_pointer by dispatching to the new
__is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 20/31] c++: Implement __is_member_object_pointer built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (18 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 19/31] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 21/31] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
                                       ` (11 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index dde83533382..9db3a60943e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3760,6 +3760,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 59aaa256232..c7e6396370d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 21/31] libstdc++: Optimize std::is_member_object_pointer compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (19 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 20/31] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 22/31] c++: Implement __is_reference built-in trait Ken Matsui
                                       ` (10 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_object_pointer by dispatching to the new
__is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 22/31] c++: Implement __is_reference built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (20 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 21/31] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 23/31] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
                                       ` (9 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9db3a60943e..e05d4fa4d20 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3788,6 +3788,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c7e6396370d..cd17cd176cb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 23/31] libstdc++: Optimize std::is_reference compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (21 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 22/31] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 24/31] c++: Implement __is_function built-in trait Ken Matsui
                                       ` (8 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_reference
by dispatching to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 24/31] c++: Implement __is_function built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (22 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 23/31] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 25/31] libstdc++: Optimize std::is_function compilation performance Ken Matsui
                                       ` (7 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index e05d4fa4d20..c394657d6b9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3751,6 +3751,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cd17cd176cb..8118d3104c7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 25/31] libstdc++: Optimize std::is_function compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (23 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 24/31] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 26/31] c++: Implement __is_object built-in trait Ken Matsui
                                       ` (6 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_function
by dispatching to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..bd57488824b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,18 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 26/31] c++: Implement __is_object built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (24 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 25/31] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 27/31] libstdc++: Optimize std::is_object compilation performance Ken Matsui
                                       ` (5 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_object.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_object.
	* g++.dg/ext/is_object.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 +++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/semantics.cc                      |  6 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
 gcc/testsuite/g++.dg/ext/is_object.C     | 29 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c394657d6b9..444dbaacd78 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
 	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
+    case CPTK_IS_OBJECT:
+      inform (loc, "  %qT is not an object type", t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..191a86307fc 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8118d3104c7..e3f71ff5902 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
       return is_nothrow_convertible (type1, type2);
 
+    case CPTK_IS_OBJECT:
+      return (type_code1 != FUNCTION_TYPE
+	      && type_code1 != REFERENCE_TYPE
+	      && type_code1 != VOID_TYPE);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12412,6 +12417,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_OBJECT:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..163be1d710b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -116,6 +116,9 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__is_object)
+# error "__has_builtin (__is_object) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_object.C b/gcc/testsuite/g++.dg/ext/is_object.C
new file mode 100644
index 00000000000..5c759a5ef69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_object.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);				\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_NON_VOLATILE(__is_object, int (int), false);
+SA_TEST_NON_VOLATILE(__is_object, ClassType (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_object,
+		     float (int, float, int[], int&), false);
+SA_TEST_CATEGORY(__is_object, int&, false);
+SA_TEST_CATEGORY(__is_object, ClassType&, false);
+SA_TEST_NON_VOLATILE(__is_object, int(&)(int), false);
+SA_TEST_CATEGORY(__is_object, void, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_object, ClassType, true);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 27/31] libstdc++: Optimize std::is_object compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (25 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 26/31] c++: Implement __is_object built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 28/31] c++: Implement __remove_pointer built-in trait Ken Matsui
                                       ` (4 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_object
by dispatching to the new __is_object built-in trait.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_object built-in trait.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bd57488824b..a12a35c209b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<__is_object(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3305,8 +3312,15 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+template <typename _Tp>
+  inline constexpr bool is_object_v = __is_object(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 28/31] c++: Implement __remove_pointer built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (26 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 27/31] libstdc++: Optimize std::is_object compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 29/31] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
                                       ` (3 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 191a86307fc..1f405f61861 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -98,6 +98,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e3f71ff5902..45584e9045f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12494,6 +12494,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 163be1d710b..719902d3f1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -176,6 +176,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 29/31] libstdc++: Optimize std::remove_pointer compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (27 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 28/31] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 30/31] c++: Implement __is_pointer built-in trait Ken Matsui
                                       ` (2 subsequent siblings)
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::remove_pointer
by dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index a12a35c209b..50210297121 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2103,6 +2103,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2111,11 +2117,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 30/31] c++: Implement __is_pointer built-in trait
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (28 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 29/31] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-17 11:36                     ` [PATCH v22 31/31] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C    | 51 ++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 444dbaacd78..9fce36e12d1 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3791,6 +3791,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1f405f61861..05514a51c21 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45584e9045f..7cccbae5287 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12216,6 +12216,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12418,6 +12421,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_OBJECT:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 719902d3f1a..b1430e9bd8b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -125,6 +125,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v22 31/31] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (29 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 30/31] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-17 11:36                     ` Ken Matsui
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
  31 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-17 11:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the compilation performance of std::is_pointer
by dispatching to the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..246f2cc0b17 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 50210297121..acd117cfa73 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node
  2023-10-17 11:36                     ` [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-17 17:04                       ` Patrick Palka
  0 siblings, 0 replies; 623+ messages in thread
From: Patrick Palka @ 2023-10-17 17:04 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Patrick Palka

On Tue, 17 Oct 2023, Ken Matsui wrote:

> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.cc (c_common_reswords): Remove all mappings of
> 	built-in traits.
> 	* c-common.h (enum rid): Remove all RID values for built-in traits.
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
> 	cases for built-in traits.  Check for built-in traits via
> 	the new cik_trait kind.
> 	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
> 	addr_space_t.
> 	(struct cp_trait): New struct to hold trait information.
> 	(cp_traits): New array to hold a mapping to all traits.
> 	(num_cp_traits): New variable to hold the size of cp_traits.
> 	(cik_reserved_for_udlit): Rename to ...
> 	(cik_trait): ... this.
> 	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> 	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> 	* lex.cc (init_cp_traits): New function to set cik_trait and
> 	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
> 	(cxx_init): Call init_cp_traits function.
> 	* parser.cc (cp_traits): Define its values, declared in cp-tree.h.
> 	(num_cp_traits): Define its value, declared in cp-tree.h.
> 	(cp_lexer_lookup_trait): New function to look up a
> 	built-in trait by IDENTIFIER_CP_INDEX.
> 	(cp_lexer_lookup_trait_expr): Likewise, look up an
> 	expression-yielding built-in trait.
> 	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> 	built-in trait.
> 	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> 	for built-in traits.
> 	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
> 	type-yielding built-in traits.
> 	(cp_parser_primary_expression): Remove all RID value cases for
> 	built-in traits.  Handle expression-yielding built-in traits.
> 	(cp_parser_trait): Handle cp_trait instead of enum rid.
> 	(cp_parser_simple_type_specifier): Remove all RID value cases
> 	for built-in traits.  Handle type-yielding built-in traits.
> 
> Co-authored-by: Patrick Palka <ppalka@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |   7 ---
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h          |  33 ++++++++---
>  gcc/cp/lex.cc             |  21 +++++++
>  gcc/cp/parser.cc          | 120 +++++++++++++++++++++++++-------------
>  6 files changed, 129 insertions(+), 65 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",		RID_WCHAR,	D_CXXONLY },
>    { "while",		RID_WHILE,	0 },
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,		RID_##CODE,	D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
> -
>    /* C++ transactional memory.  */
>    { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>    { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>  
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>  
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
>  	}
>      }
>  
> +  /* Check for built-in traits.  */
> +  if (IDENTIFIER_TRAIT_P (id))
> +    return true;
> +
>    /* Also detect common reserved C++ words that aren't strictly built-in
>       functions.  */
>    switch (C_RID_CODE (id))
> @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index efcd2de54e5..81a5c06a574 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
>    cik_simple_op = 4,	/* Non-assignment operator name.  */
>    cik_assign_op = 5,	/* An assignment operator name.  */
>    cik_conv_op = 6,	/* Conversion operator name.  */
> -  cik_reserved_for_udlit = 7,	/* Not yet in use  */
> +  cik_trait = 7,	/* Built-in trait name.  */
>    cik_max
>  };
>  
> @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
>      & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is for any operator name (including
> -   conversions).  Value 4, 5, 6 or 7.  */
> +   conversions).  Value 4, 5, or 6.  */
>  #define IDENTIFIER_ANY_OP_P(NODE)		\
> -  (IDENTIFIER_KIND_BIT_2 (NODE))
> +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
>  
>  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
>  #define IDENTIFIER_OVL_OP_P(NODE)		\
> @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
>     & IDENTIFIER_KIND_BIT_0 (NODE))
>  
>  /* True if this identifier is the name of a type-conversion
> -   operator.  Value 7.  */
> +   operator.  Value 6.  */
>  #define IDENTIFIER_CONV_OP_P(NODE)		\
>    (IDENTIFIER_ANY_OP_P (NODE)			\
>     & IDENTIFIER_KIND_BIT_1 (NODE)		\
>     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
>  
> +/* True if this identifier is the name of a built-in trait.  */
> +#define IDENTIFIER_TRAIT_P(NODE)		\
> +  (IDENTIFIER_KIND_BIT_0 (NODE)			\
> +   && IDENTIFIER_KIND_BIT_1 (NODE)		\
> +   && IDENTIFIER_KIND_BIT_2 (NODE))
> +
>  /* True if this identifier is a new or delete operator.  */
>  #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
>    (IDENTIFIER_OVL_OP_P (NODE)			\
> @@ -1375,16 +1381,27 @@ struct GTY (()) tree_argument_pack_select {
>    int index;
>  };
>  
> -/* The different kinds of traits that we encounter.  */
> -
> -enum cp_trait_kind
> -{
> +/* The different kinds of traits that we encounter.  The size is limited to
> +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> +enum cp_trait_kind : addr_space_t {
>  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
>    CPTK_##CODE,
>  #include "cp-trait.def"
>  #undef DEFTRAIT
>  };
>  
> +/* The trait type.  */
> +struct cp_trait {
> +  const char *name;
> +  cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +
> +/* The trait table.  */

Let's mention that this table is indexed by cp_trait_kind.

> +extern const struct cp_trait cp_traits[];
> +extern const addr_space_t num_cp_traits;
> +
>  /* The types that we are processing.  */
>  #define TRAIT_EXPR_TYPE1(NODE) \
>    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..872ca970545 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>  
>  static int interface_strcmp (const char *);
> +static void init_cp_traits (void);
>  static void init_cp_pragma (void);
>  
>  static tree parse_strconst_pragma (const char *, int);
> @@ -283,6 +284,25 @@ init_reswords (void)
>      }
>  }
>  
> +/* Initialize the C++ traits.  */
> +static void
> +init_cp_traits (void)
> +{
> +  tree id;
> +
> +  for (unsigned int i = 0; i < num_cp_traits; ++i)
> +    {
> +      id = get_identifier (cp_traits[i].name);
> +      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
> +      set_identifier_kind (id, cik_trait);
> +    }
> +
> +  /* An alias for __is_same.  */
> +  id = get_identifier ("__is_same_as");
> +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> +  set_identifier_kind (id, cik_trait);
> +}
> +
>  static void
>  init_cp_pragma (void)
>  {
> @@ -324,6 +344,7 @@ cxx_init (void)
>    input_location = BUILTINS_LOCATION;
>  
>    init_reswords ();
> +  init_cp_traits ();
>    init_tree ();
>    init_cp_semantics ();
>    init_operators ();
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 59b9852895e..ece238c2072 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
> +static const cp_trait *cp_lexer_lookup_trait
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_expr
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_type
> +  (const cp_token *);
>  
>  static cp_token_cache *cp_token_cache_new
>    (cp_token *, cp_token *);
> @@ -279,6 +285,21 @@ static FILE *cp_lexer_debug_stream;
>     sizeof, typeof, or alignof.  */
>  int cp_unevaluated_operand;
>  
> +/* The trait table, declared in cp-tree.h.  */
> +const cp_trait cp_traits[] =
> +{
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> +  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
> +#include "cp-trait.def"
> +#undef DEFTRAIT
> +};
> +const addr_space_t num_cp_traits = ARRAY_SIZE (cp_traits);

Let's move the definition of cp_traits to lex.cc near the definition of
the similar ovl_op_info table.  I think we can in turn get rid of
num_cp_traits since the size of the array will be statically known in
lex.cc where the loop over it resides.

Otherwise this patch series looks good to me.  (Since only this patch
needs changes, feel free to send the new version as a reply to this
thread via git send-email's --in-reply-to flag instead of resending the
entire series.)

> +
> +/* The trait table cannot have more than 255 (addr_space_t) entries since
> +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> +static_assert(num_cp_traits <= 255,
> +              "cp_traits array cannot have more than 255 entries");
> +
>  /* Dump up to NUM tokens in BUFFER to FILE starting with token
>     START_TOKEN.  If START_TOKEN is NULL, the dump starts with the
>     first token in BUFFER.  If NUM is 0, dump all the tokens.  If
> @@ -1167,12 +1188,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      case RID_CONSTEVAL:
>        return true;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      return true;
> -
>      default:
>        if (keyword >= RID_FIRST_INT_N
>  	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> @@ -1182,6 +1197,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      }
>  }
>  
> +/* Look ups the corresponding built-in trait if a given token is
> +   a built-in trait.  Otherwise, returns nullptr.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait (const cp_token *token)
> +{
> +  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
> +    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is an expression-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_expr (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && !trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is a type-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_type (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
>  /* Return true if the next token is a keyword for a decl-specifier.  */
>  
>  static bool
> @@ -1190,6 +1243,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
>    cp_token *token;
>  
>    token = cp_lexer_peek_token (lexer);
> +  if (cp_lexer_lookup_trait_type (token))
> +    return true;
>    return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
>  
> @@ -2854,7 +2909,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, const cp_trait *);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6029,12 +6084,6 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_OFFSETOF:
>  	  return cp_parser_builtin_offsetof (parser);
>  
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -	case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -	  return cp_parser_trait (parser, token->keyword);
> -
>  	// C++ concepts
>  	case RID_REQUIRES:
>  	  return cp_parser_requires_expression (parser);
> @@ -6073,6 +6122,9 @@ cp_parser_primary_expression (cp_parser *parser,
>  	 `::' as the beginning of a qualified-id, or the "operator"
>  	 keyword.  */
>      case CPP_NAME:
> +      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
> +	return cp_parser_trait (parser, trait);
> +      /* FALLTHRU */
>      case CPP_SCOPE:
>      case CPP_TEMPLATE_ID:
>      case CPP_NESTED_NAME_SPECIFIER:
> @@ -11041,28 +11093,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>  
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
>  {
> -  cp_trait_kind kind;
> +  const cp_trait_kind kind = trait->kind;
>    tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> -
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:			 \
> -      kind = CPTK_##CODE;		 \
> -      binary = (ARITY == 2);		 \
> -      variadic = (ARITY == -1);		 \
> -      type = (TCC == tcc_type);		 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  const bool binary = (trait->arity == 2);
> +  const bool variadic = (trait->arity == -1);
> +  const bool type = trait->type;
>  
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -20089,20 +20126,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>  
>        return type;
>  
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    default:
> +      break;
> +    }
> +
> +  /* If token is a type-yielding built-in traits, parse it.  */
> +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> +  if (trait)
> +    {
> +      type = cp_parser_trait (parser, trait);
>        if (decl_specs)
>  	cp_parser_set_decl_spec_type (decl_specs, type,
>  				      token,
>  				      /*type_definition_p=*/false);
>  
>        return type;
> -
> -    default:
> -      break;
>      }
>  
>    /* If token is an already-parsed decltype not followed by ::,
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 00/33] Optimize type traits performance
  2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
                                       ` (30 preceding siblings ...)
  2023-10-17 11:36                     ` [PATCH v22 31/31] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                     ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 01/33] c++: Sort built-in traits alphabetically Ken Matsui
                                         ` (33 more replies)
  31 siblings, 34 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v23:

	* Improved the comment in cp-tree.h.
	* Moved the definition of cp_traits to lex.cc from parser.cc.
	* Implemented __is_invocable built-in trait.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (33):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize std::is_const compilation performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize std::is_volatile compilation performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize std::is_unbounded_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize std::is_pointer compilation performance
  c++: Implement __is_invocable built-in trait
  libstdc++: Optimize std::is_invocable compilation performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/constraint.cc			       | 109 ++++--
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait.def			       |  25 +-
 gcc/cp/cp-tree.h			       |  32 +-
 gcc/cp/lex.cc				       |  34 ++
 gcc/cp/method.h			       |  28 ++
 gcc/cp/parser.cc			       | 118 +++---
 gcc/cp/semantics.cc			       | 284 ++++++++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 113 ++++--
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 +
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++
 gcc/testsuite/g++.dg/ext/is_invocable1.C      | 337 ++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable2.C      | 139 ++++++++
 gcc/testsuite/g++.dg/ext/is_invocable3.C      |  51 +++
 gcc/testsuite/g++.dg/ext/is_invocable4.C      |  33 ++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_object.C	       |  29 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 +++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 +
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 219 +++++++++++-
 .../is_invocable/incomplete_args_neg.cc       |   1 +
 .../20_util/is_invocable/incomplete_neg.cc    |   1 +
 33 files changed, 1878 insertions(+), 196 deletions(-)
 create mode 100644 gcc/cp/method.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 01/33] c++: Sort built-in traits alphabetically
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                         ` (32 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 64b64e17857..41fe2812ac4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3703,18 +3703,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3730,6 +3748,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3749,50 +3779,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 2a0cf963e91..144cb440fa3 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 01/33] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 19:11                         ` Patrick Palka
  2023-10-23 20:27                         ` Jason Merrill
  2023-10-20 13:53                       ` [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
                                         ` (31 subsequent siblings)
  33 siblings, 2 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used approximately
once in a C++ translation unit, this patch removes all RID values for built-in
traits and uses the identifier node to look up the specific trait.  Rather
than holding traits as keywords, we set all trait identifiers as cik_trait,
which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (cp_traits): Define its values, declared in cp-tree.h.
	(init_cp_traits): New function to set cik_trait and
	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 ---
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  32 +++++++++---
 gcc/cp/lex.cc             |  34 ++++++++++++
 gcc/cp/parser.cc          | 105 +++++++++++++++++++++++---------------
 6 files changed, 126 insertions(+), 65 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index efcd2de54e5..e62e4df4db0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   && IDENTIFIER_KIND_BIT_1 (NODE)		\
+   && IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1375,16 +1381,26 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  const char *name;
+  cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+
+/* The trait table indexed by cp_trait_kind.  */
+extern const struct cp_trait cp_traits[];
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..a939e2e5f13 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -97,6 +98,19 @@ ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
 unsigned char ovl_op_mapping[MAX_TREE_CODES];
 unsigned char ovl_op_alternate[OVL_OP_MAX];
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(ARRAY_SIZE (cp_traits) <= 255,
+	      "cp_traits array cannot have more than 255 entries");
+
 /* Get the name of the kind of identifier T.  */
 
 const char *
@@ -283,6 +297,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+  for (unsigned int i = 0; i < ARRAY_SIZE (cp_traits); ++i)
+    {
+      id = get_identifier (cp_traits[i].name);
+      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
+      set_identifier_kind (id, cik_trait);
+    }
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +357,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 59b9852895e..f87d4c0a855 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1167,12 +1173,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1182,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
+    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1228,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2894,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6029,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6073,6 +6107,9 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+	return cp_parser_trait (parser, trait);
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11041,28 +11078,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
+  const cp_trait_kind kind = trait->kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
+  const bool type = trait->type;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -20089,20 +20111,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 01/33] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-23 20:36                         ` Jason Merrill
  2023-10-20 13:53                       ` [PATCH v23 04/33] c++: Implement __is_const built-in trait Ken Matsui
                                         ` (30 subsequent siblings)
  33 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 47 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f87d4c0a855..8b6c01e52c2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1182,15 +1182,27 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1198,9 +1210,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1211,9 +1223,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1228,7 +1240,7 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6107,7 +6119,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait
+	  = cp_lexer_peek_trait_expr (parser->lexer, token))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20116,7 +20129,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 04/33] c++: Implement __is_const built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (2 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
                                         ` (29 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41fe2812ac4..41d9eef7227 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 144cb440fa3..7fbcfd7ccad 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 05/33] libstdc++: Optimize std::is_const compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (3 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 04/33] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
                                         ` (28 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_const
by dispatching to the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 06/33] c++: Implement __is_volatile built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (4 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
                                         ` (27 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41d9eef7227..54782a167dd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7fbcfd7ccad..7726fa99711 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 07/33] libstdc++: Optimize std::is_volatile compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (5 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 08/33] c++: Implement __is_array built-in trait Ken Matsui
                                         ` (26 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_volatile
by dispatching to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile built-in
	trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 08/33] c++: Implement __is_array built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (6 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
                                         ` (25 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 54782a167dd..b9f89fe178c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3715,6 +3715,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7726fa99711..8d5874d6ab0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 09/33] libstdc++: Optimize std::is_array compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (7 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 08/33] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                         ` (24 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_array
by dispatching to the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 10/33] c++: Implement __is_unbounded_array built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (8 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
                                         ` (23 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b9f89fe178c..292b941e6a0 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5874d6ab0..bd73323e6db 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (9 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                         ` (22 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_unbounded_array
by dispatching to the new __is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 12/33] c++: Implement __is_bounded_array built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (10 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
                                         ` (21 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 292b941e6a0..71a40558881 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bd73323e6db..aab35c9e5ba 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 13/33] libstdc++: Optimize std::is_bounded_array compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (11 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                         ` (20 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_bounded_array
by dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use __is_bounded_array
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 14/33] c++: Implement __is_scoped_enum built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (12 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
                                         ` (19 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 71a40558881..2b46e3afa97 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3782,6 +3782,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index aab35c9e5ba..9f0e468f489 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (13 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                         ` (18 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_scoped_enum
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 16/33] c++: Implement __is_member_pointer built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (14 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
                                         ` (17 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2b46e3afa97..a969a069db4 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9f0e468f489..5ca05dde75d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 17/33] libstdc++: Optimize std::is_member_pointer compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (15 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                         ` (16 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_member_pointer
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use __is_member_pointer
	built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 18/33] c++: Implement __is_member_function_pointer built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (16 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
                                         ` (15 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a969a069db4..dde83533382 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5ca05dde75d..59aaa256232 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (17 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                         ` (14 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_function_pointer by dispatching to the new
__is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 20/33] c++: Implement __is_member_object_pointer built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (18 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
                                         ` (13 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index dde83533382..9db3a60943e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3760,6 +3760,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 59aaa256232..c7e6396370d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (19 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 22/33] c++: Implement __is_reference built-in trait Ken Matsui
                                         ` (12 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_object_pointer by dispatching to the new
__is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 22/33] c++: Implement __is_reference built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (20 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
                                         ` (11 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9db3a60943e..e05d4fa4d20 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3788,6 +3788,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c7e6396370d..cd17cd176cb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 23/33] libstdc++: Optimize std::is_reference compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (21 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 22/33] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 24/33] c++: Implement __is_function built-in trait Ken Matsui
                                         ` (10 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_reference
by dispatching to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference built-in
	trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 24/33] c++: Implement __is_function built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (22 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
                                         ` (9 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index e05d4fa4d20..c394657d6b9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3751,6 +3751,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cd17cd176cb..8118d3104c7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 25/33] libstdc++: Optimize std::is_function compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (23 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 24/33] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 26/33] c++: Implement __is_object built-in trait Ken Matsui
                                         ` (8 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_function
by dispatching to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function built-in
	trait.
	(is_function_v): Likewise. Optimize its implementation.
	(is_const_v): Move on top of is_function_v as is_function_v now
	depends on is_const_v.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 39 ++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..1e561c8ea38 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,28 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_const_v = false;
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+template <typename _Tp>
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
@@ -3303,16 +3330,6 @@ template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
 #endif
 
-#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
-template <typename _Tp>
-  inline constexpr bool is_const_v = __is_const(_Tp);
-#else
-template <typename _Tp>
-  inline constexpr bool is_const_v = false;
-template <typename _Tp>
-  inline constexpr bool is_const_v<const _Tp> = true;
-#endif
-
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
 template <typename _Tp>
   inline constexpr bool is_volatile_v = __is_volatile(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 26/33] c++: Implement __is_object built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (24 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
                                         ` (7 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_object.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_object.
	* g++.dg/ext/is_object.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 +++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/semantics.cc                      |  6 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
 gcc/testsuite/g++.dg/ext/is_object.C     | 29 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c394657d6b9..444dbaacd78 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
 	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
+    case CPTK_IS_OBJECT:
+      inform (loc, "  %qT is not an object type", t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..191a86307fc 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8118d3104c7..e3f71ff5902 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
       return is_nothrow_convertible (type1, type2);
 
+    case CPTK_IS_OBJECT:
+      return (type_code1 != FUNCTION_TYPE
+	      && type_code1 != REFERENCE_TYPE
+	      && type_code1 != VOID_TYPE);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12412,6 +12417,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_OBJECT:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..163be1d710b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -116,6 +116,9 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__is_object)
+# error "__has_builtin (__is_object) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_object.C b/gcc/testsuite/g++.dg/ext/is_object.C
new file mode 100644
index 00000000000..5c759a5ef69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_object.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);				\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_NON_VOLATILE(__is_object, int (int), false);
+SA_TEST_NON_VOLATILE(__is_object, ClassType (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_object,
+		     float (int, float, int[], int&), false);
+SA_TEST_CATEGORY(__is_object, int&, false);
+SA_TEST_CATEGORY(__is_object, ClassType&, false);
+SA_TEST_NON_VOLATILE(__is_object, int(&)(int), false);
+SA_TEST_CATEGORY(__is_object, void, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_object, ClassType, true);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 27/33] libstdc++: Optimize std::is_object compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (25 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 26/33] c++: Implement __is_object built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
                                         ` (6 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_object
by dispatching to the new __is_object built-in trait.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_object built-in trait.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 1e561c8ea38..80ec0fd5475 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<__is_object(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3315,8 +3322,15 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+template <typename _Tp>
+  inline constexpr bool is_object_v = __is_object(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 28/33] c++: Implement __remove_pointer built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (26 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
                                         ` (5 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 191a86307fc..1f405f61861 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -98,6 +98,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e3f71ff5902..45584e9045f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12494,6 +12494,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 163be1d710b..719902d3f1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -176,6 +176,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 29/33] libstdc++: Optimize std::remove_pointer compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (27 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
                                         ` (4 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::remove_pointer
by dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 80ec0fd5475..0641ecfdf2b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2103,6 +2103,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2111,11 +2117,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 30/33] c++: Implement __is_pointer built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (28 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
                                         ` (3 subsequent siblings)
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C    | 51 ++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 444dbaacd78..9fce36e12d1 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3791,6 +3791,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1f405f61861..05514a51c21 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45584e9045f..7cccbae5287 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12216,6 +12216,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12418,6 +12421,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_OBJECT:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 719902d3f1a..b1430e9bd8b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -125,6 +125,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (29 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-22 12:06                         ` Ken Matsui
  2023-10-20 13:53                       ` [PATCH v23 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
                                         ` (2 subsequent siblings)
  33 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the compilation performance of std::is_pointer
by dispatching to the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.
	* include/std/type_traits (is_pointer): Likewise. Optimize its
	implementation.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..246f2cc0b17 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
+    {
+      enum { __value = __is_pointer(_Tp) };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       enum { __value = 1 };
       typedef __true_type __type;
     };
+#endif
 
   //
   // An arithmetic type is an integer type or a floating point type
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 0641ecfdf2b..75a94cb8d7e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (30 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 21:29                         ` Patrick Palka
  2023-10-20 13:53                       ` [PATCH v23 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
  2023-10-20 16:16                       ` [PATCH v24 00/33] Optimize type traits performance Ken Matsui
  33 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_invocable.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(is_invocable_p): New function.
	* method.h: New file to export build_trait_object in method.cc.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
	* g++.dg/ext/is_invocable1.C: New test.
	* g++.dg/ext/is_invocable2.C: New test.
	* g++.dg/ext/is_invocable3.C: New test.
	* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   6 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/method.h                          |  28 ++
 gcc/cp/semantics.cc                      | 135 +++++++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 ++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 ++++
 gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
 9 files changed, 733 insertions(+)
 create mode 100644 gcc/cp/method.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9fce36e12d1..29bf548d30a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3754,6 +3754,12 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FUNCTION:
       inform (loc, "  %qT is not a function", t1);
       break;
+    case CPTK_IS_INVOCABLE:
+      if (!t2)
+    inform (loc, "  %qT is not invocable", t1);
+      else
+    inform (loc, "  %qT is not invocable by %qE", t1, t2);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 05514a51c21..b8b7608c122 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/method.h b/gcc/cp/method.h
new file mode 100644
index 00000000000..1aec8ec5cfd
--- /dev/null
+++ b/gcc/cp/method.h
@@ -0,0 +1,28 @@
+/* Functions exported by method.cc.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_METHOD_H
+#define GCC_CP_METHOD_H 1
+
+#include "tree.h"
+
+/* In method.cc  */
+extern tree build_trait_object (tree type);
+
+#endif  /* GCC_CP_METHOD_H  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7cccbae5287..cc2e400531a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "predict.h"
 #include "memmodel.h"
+#include "method.h"
+
+#include "print-tree.h"
+#include "tree-pretty-print.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
@@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
   return saw_copy;
 }
 
+/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
+
+static bool
+is_invocable_p (tree fn_type, tree arg_types)
+{
+  /* ARG_TYPES must be a TREE_VEC.  */
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* std::is_invocable is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+    {
+      tree deref_fn_type = TREE_TYPE (fn_type);
+      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+      /* Dereference fn_type if it is a pointer to member.  */
+      if (is_ptrdatamem || is_ptrmemfunc)
+	fn_type = deref_fn_type;
+    }
+  else
+    {
+      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+    }
+
+  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
+    /* A pointer to data member with non-one argument is not invocable.  */
+    return false;
+
+  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
+    /* A pointer to member function with no arguments is not invocable.  */
+    return false;
+
+  /* Construct an expression of a pointer to member.  */
+  tree datum;
+  if (is_ptrdatamem || is_ptrmemfunc)
+    {
+      tree datum_type = TREE_VEC_ELT (arg_types, 0);
+
+      /* Dereference datum.  */
+      if (CLASS_TYPE_P (datum_type))
+	{
+	  bool is_refwrap = false;
+
+	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
+	  if (decl_in_std_namespace_p (datum_decl))
+	    {
+	      tree name = DECL_NAME (datum_decl);
+	      if (name && (id_equal (name, "reference_wrapper")))
+		{
+		  /* Handle std::reference_wrapper.  */
+		  is_refwrap = true;
+		  datum_type = cp_build_reference_type (datum_type, false);
+		}
+	    }
+
+	  datum = build_trait_object (datum_type);
+
+	  /* If datum_type was not std::reference_wrapper, check if it has
+	     operator*() overload.  If datum_type was std::reference_wrapper,
+	     avoid dereferencing the datum twice.  */
+	  if (!is_refwrap)
+	    if (get_class_binding (datum_type, get_identifier ("operator*")))
+	      /* Handle operator*().  */
+	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
+					    RO_UNARY_STAR, NULL_TREE,
+					    tf_none);
+	}
+      else if (POINTER_TYPE_P (datum_type))
+	datum = build_trait_object (TREE_TYPE (datum_type));
+      else
+	datum = build_trait_object (datum_type);
+    }
+
+  /* Build a function expression.  */
+  tree fn;
+  if (is_ptrdatamem)
+    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
+  else if (is_ptrmemfunc)
+    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
+  else
+    fn = build_trait_object (fn_type);
+
+  /* Construct arguments to the function and an expression of a call.  */
+  if (!is_ptrdatamem)
+    {
+      releasing_vec args;
+
+      if (is_ptrmemfunc)
+	{
+	  /* A pointer to member function is internally converted to a pointer
+	     to function that takes a pointer to the dereferenced datum type
+	     as its first argument and original arguments afterward.  If the
+	     function is a const member function, the first argument also
+	     requires a const datum pointer and vice-versa.  */
+
+	  tree datum_type = TREE_TYPE (datum);
+	  if (TYPE_REF_P (datum_type))
+	    datum_type = TREE_TYPE (datum_type);
+
+	  datum = build_trait_object (build_pointer_type (datum_type));
+	  vec_safe_push (args, datum);
+	}
+
+      for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
+	{
+	  tree arg_type = TREE_VEC_ELT (arg_types, i);
+	  tree arg = build_trait_object (arg_type);
+	  vec_safe_push (args, arg);
+	}
+
+      fn = finish_call_expr (fn, &args, false, false, tf_none);
+    }
+
+  if (error_operand_p (fn))
+    return false;
+
+  return true;
+}
+
 /* Return true if DERIVED is pointer interconvertible base of BASE.  */
 
 static bool
@@ -12181,6 +12312,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FUNCTION:
       return type_code1 == FUNCTION_TYPE;
 
+    case CPTK_IS_INVOCABLE:
+      return is_invocable_p (type1, type2);
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12524,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CONVERTIBLE:
+    case CPTK_IS_INVOCABLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b1430e9bd8b..3a9bda1ee03 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -92,6 +92,9 @@
 #if !__has_builtin (__is_function)
 # error "__has_builtin (__is_function) failed"
 #endif
+#if !__has_builtin (__is_invocable)
+# error "__has_builtin (__is_invocable) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable1.C b/gcc/testsuite/g++.dg/ext/is_invocable1.C
new file mode 100644
index 00000000000..2fd3906b571
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable1.C
@@ -0,0 +1,337 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+using func_type_v0 = void(*)();
+
+SA(   __is_invocable( func_type_v0 ) );
+SA( ! __is_invocable( func_type_v0, int ) );
+
+using func_type_i0 = int(*)();
+
+SA(   __is_invocable( func_type_i0 ) );
+SA( ! __is_invocable( func_type_i0, int ) );
+
+using func_type_l0 = int&(*)();
+
+SA(   __is_invocable( func_type_l0 ) );
+SA( ! __is_invocable( func_type_l0(int) ) );
+
+using func_type_ii = int(*)(int);
+
+SA( ! __is_invocable( func_type_ii ) );
+SA(   __is_invocable( func_type_ii, int ) );
+
+using func_type_il = int(*)(int&);
+
+SA( ! __is_invocable( func_type_il ) );
+SA( ! __is_invocable( func_type_il, int ) );
+SA(   __is_invocable( func_type_il, int& ) );
+
+using func_type_ir = int(*)(int&&);
+
+SA( ! __is_invocable( func_type_ir ) );
+SA( ! __is_invocable( func_type_ir, int& ) );
+SA(   __is_invocable( func_type_ir, int ) );
+SA(   __is_invocable( func_type_ir, int&& ) );
+
+struct A { };
+
+using mem_type_i = int A::*;
+
+SA( ! __is_invocable( mem_type_i ) );
+SA( ! __is_invocable( mem_type_i, int ) );
+SA( ! __is_invocable( mem_type_i, int* ) );
+SA( ! __is_invocable( mem_type_i, int& ) );
+SA( ! __is_invocable( mem_type_i, int&& ) );
+SA(   __is_invocable( mem_type_i, A ) );
+SA(   __is_invocable( mem_type_i, A* ) );
+SA(   __is_invocable( mem_type_i, A& ) );
+SA(   __is_invocable( mem_type_i, A&& ) );
+SA(   __is_invocable( mem_type_i, const A& ) );
+SA( ! __is_invocable( mem_type_i, A&, int ) );
+
+using memfun_type_i = int (A::*)();
+
+SA( ! __is_invocable( memfun_type_i ) );
+SA( ! __is_invocable( memfun_type_i, int ) );
+SA( ! __is_invocable( memfun_type_i, int* ) );
+SA( ! __is_invocable( memfun_type_i, int& ) );
+SA( ! __is_invocable( memfun_type_i, int&& ) );
+SA(   __is_invocable( memfun_type_i, A ) );
+SA(   __is_invocable( memfun_type_i, A* ) );
+SA(   __is_invocable( memfun_type_i, A& ) );
+SA(   __is_invocable( memfun_type_i, A&& ) );
+SA( ! __is_invocable( memfun_type_i, const A& ) );
+SA( ! __is_invocable( memfun_type_i, A&, int ) );
+
+using memfun_type_ic = int (A::*)() const;
+
+SA( ! __is_invocable( memfun_type_ic ) );
+SA( ! __is_invocable( memfun_type_ic, int ) );
+SA( ! __is_invocable( memfun_type_ic, int& ) );
+SA(   __is_invocable( memfun_type_ic, A& ) );
+SA(   __is_invocable( memfun_type_ic, A* ) );
+SA( ! __is_invocable( memfun_type_ic, A&, int ) );
+SA( ! __is_invocable( memfun_type_ic, A*, int& ) );
+SA(   __is_invocable( memfun_type_ic, const A& ) );
+SA(   __is_invocable( memfun_type_ic, const A* ) );
+SA( ! __is_invocable( memfun_type_ic, const A&, int& ) );
+SA( ! __is_invocable( memfun_type_ic, const A*, int ) );
+
+using memfun_type_iic = int& (A::*)(int&) const;
+
+SA( ! __is_invocable( memfun_type_iic ) );
+SA( ! __is_invocable( memfun_type_iic, int ) );
+SA( ! __is_invocable( memfun_type_iic, int& ) );
+SA( ! __is_invocable( memfun_type_iic, A&, int ) );
+SA(   __is_invocable( memfun_type_iic, A&, int& ) );
+SA( ! __is_invocable( memfun_type_iic, A*, int ) );
+SA(   __is_invocable( memfun_type_iic, A*, int& ) );
+SA( ! __is_invocable( memfun_type_iic, const A&, int ) );
+SA( ! __is_invocable( memfun_type_iic, const A&, int&, int ) );
+SA(   __is_invocable( memfun_type_iic, const A&, int& ) );
+SA(   __is_invocable( memfun_type_iic, const A*, int& ) );
+
+struct B {
+  int& operator()();
+  long& operator()() const;
+  bool& operator()(int);
+private:
+  void operator()(int, int);
+};
+using CB = const B;
+
+SA(   __is_invocable( B ) );
+SA(   __is_invocable( B& ) );
+SA(   __is_invocable( B&& ) );
+SA( ! __is_invocable( B* ) );
+SA(   __is_invocable( CB ) );
+SA(   __is_invocable( CB& ) );
+SA( ! __is_invocable( CB* ) );
+
+SA(   __is_invocable( B, int ) );
+SA(   __is_invocable( B&, int ) );
+SA(   __is_invocable( B&&, int ) );
+SA( ! __is_invocable( B*, int ) );
+SA( ! __is_invocable( CB, int ) );
+SA( ! __is_invocable( CB&, int ) );
+SA( ! __is_invocable( CB*, int ) );
+
+SA( ! __is_invocable( B, int, int ) );
+SA( ! __is_invocable( B&, int, int ) );
+SA( ! __is_invocable( B&&, int, int ) );
+SA( ! __is_invocable( B*, int, int ) );
+SA( ! __is_invocable( CB, int, int ) );
+SA( ! __is_invocable( CB&, int, int ) );
+SA( ! __is_invocable( CB*, int, int ) );
+
+struct C : B { int& operator()() = delete; };
+using CC = const C;
+
+SA( ! __is_invocable( C ) );
+SA( ! __is_invocable( C& ) );
+SA( ! __is_invocable( C&& ) );
+SA( ! __is_invocable( C* ) );
+SA( ! __is_invocable( CC ) );
+SA( ! __is_invocable( CC& ) );
+SA( ! __is_invocable( CC* ) );
+
+struct D { B operator*(); };
+using CD = const D;
+
+SA( ! __is_invocable( D ) );
+
+struct E { void v(); };
+using CE = const E;
+
+SA( ! __is_invocable( E ) );
+SA( ! __is_invocable( void (E::*)() ) );
+SA(   __is_invocable( void (E::*)(), E ) );
+SA(   __is_invocable( void (E::*)(), E* ) );
+SA( ! __is_invocable( void (E::*)(), CE ) );
+
+struct F : E {};
+using CF = const F;
+
+SA( ! __is_invocable( F ) );
+SA(   __is_invocable( void (E::*)(), F ) );
+SA(   __is_invocable( void (E::*)(), F* ) );
+SA( ! __is_invocable( void (E::*)(), CF ) );
+
+struct G { E operator*(); };
+using CG = const G;
+
+SA( ! __is_invocable( G ) );
+SA(   __is_invocable( void (E::*)(), G ) );
+SA( ! __is_invocable( void (E::*)(), G* ) );
+SA( ! __is_invocable( void (E::*)(), CG ) );
+
+struct H { E& operator*(); };
+using CH = const H;
+
+SA( ! __is_invocable( H ) );
+SA(   __is_invocable( void (E::*)(), H ) );
+SA( ! __is_invocable( void (E::*)(), H* ) );
+SA( ! __is_invocable( void (E::*)(), CH ) );
+
+struct I { E&& operator*(); };
+using CI = const I;
+
+SA( ! __is_invocable( I ) );
+SA(   __is_invocable( void (E::*)(), I ) );
+SA( ! __is_invocable( void (E::*)(), I* ) );
+SA( ! __is_invocable( void (E::*)(), CI ) );
+
+struct K { E* operator*(); };
+using CK = const K;
+
+SA( ! __is_invocable( K ) );
+SA( ! __is_invocable( void (E::*)(), K ) );
+SA( ! __is_invocable( void (E::*)(), K* ) );
+SA( ! __is_invocable( void (E::*)(), CK ) );
+
+struct L { CE operator*(); };
+using CL = const L;
+
+SA( ! __is_invocable( L ) );
+SA( ! __is_invocable( void (E::*)(), L ) );
+SA( ! __is_invocable( void (E::*)(), L* ) );
+SA( ! __is_invocable( void (E::*)(), CL ) );
+
+struct M {
+  int i;
+private:
+  long l;
+};
+using CM = const M;
+
+SA( ! __is_invocable( M ) );
+SA( ! __is_invocable( M& ) );
+SA( ! __is_invocable( M&& ) );
+SA( ! __is_invocable( M* ) );
+SA( ! __is_invocable( CM ) );
+SA( ! __is_invocable( CM& ) );
+SA( ! __is_invocable( CM* ) );
+
+SA( ! __is_invocable( int M::* ) );
+SA(   __is_invocable( int M::*, M ) );
+SA(   __is_invocable( int M::*, M& ) );
+SA(   __is_invocable( int M::*, M&& ) );
+SA(   __is_invocable( int M::*, M* ) );
+SA(   __is_invocable( int M::*, CM ) );
+SA(   __is_invocable( int M::*, CM& ) );
+SA(   __is_invocable( int M::*, CM* ) );
+SA( ! __is_invocable( int M::*, int ) );
+
+SA( ! __is_invocable( int CM::* ) );
+SA(   __is_invocable( int CM::*, M ) );
+SA(   __is_invocable( int CM::*, M& ) );
+SA(   __is_invocable( int CM::*, M&& ) );
+SA(   __is_invocable( int CM::*, M* ) );
+SA(   __is_invocable( int CM::*, CM ) );
+SA(   __is_invocable( int CM::*, CM& ) );
+SA(   __is_invocable( int CM::*, CM* ) );
+SA( ! __is_invocable( int CM::*, int ) );
+
+SA( ! __is_invocable( long M::* ) );
+SA(   __is_invocable( long M::*, M ) );
+SA(   __is_invocable( long M::*, M& ) );
+SA(   __is_invocable( long M::*, M&& ) );
+SA(   __is_invocable( long M::*, M* ) );
+SA(   __is_invocable( long M::*, CM ) );
+SA(   __is_invocable( long M::*, CM& ) );
+SA(   __is_invocable( long M::*, CM* ) );
+SA( ! __is_invocable( long M::*, long ) );
+
+SA( ! __is_invocable( long CM::* ) );
+SA(   __is_invocable( long CM::*, M ) );
+SA(   __is_invocable( long CM::*, M& ) );
+SA(   __is_invocable( long CM::*, M&& ) );
+SA(   __is_invocable( long CM::*, M* ) );
+SA(   __is_invocable( long CM::*, CM ) );
+SA(   __is_invocable( long CM::*, CM& ) );
+SA(   __is_invocable( long CM::*, CM* ) );
+SA( ! __is_invocable( long CM::*, long ) );
+
+SA( ! __is_invocable( short M::* ) );
+SA(   __is_invocable( short M::*, M ) );
+SA(   __is_invocable( short M::*, M& ) );
+SA(   __is_invocable( short M::*, M&& ) );
+SA(   __is_invocable( short M::*, M* ) );
+SA(   __is_invocable( short M::*, CM ) );
+SA(   __is_invocable( short M::*, CM& ) );
+SA(   __is_invocable( short M::*, CM* ) );
+SA( ! __is_invocable( short M::*, short ) );
+
+SA( ! __is_invocable( short CM::* ) );
+SA(   __is_invocable( short CM::*, M ) );
+SA(   __is_invocable( short CM::*, M& ) );
+SA(   __is_invocable( short CM::*, M&& ) );
+SA(   __is_invocable( short CM::*, M* ) );
+SA(   __is_invocable( short CM::*, CM ) );
+SA(   __is_invocable( short CM::*, CM& ) );
+SA(   __is_invocable( short CM::*, CM* ) );
+SA( ! __is_invocable( short CM::*, short ) );
+
+struct N { M operator*(); };
+SA(   __is_invocable( int M::*, N ) );
+SA( ! __is_invocable( int M::*, N* ) );
+
+struct O { M& operator*(); };
+SA(   __is_invocable( int M::*, O ) );
+SA( ! __is_invocable( int M::*, O* ) );
+
+struct P { M&& operator*(); };
+SA(   __is_invocable( int M::*, P ) );
+SA( ! __is_invocable( int M::*, P* ) );
+
+struct Q { M* operator*(); };
+SA( ! __is_invocable( int M::*, Q ) );
+SA( ! __is_invocable( int M::*, Q* ) );
+
+struct R { void operator()(int = 0); };
+
+SA(   __is_invocable( R ) );
+SA(   __is_invocable( R, int ) );
+SA( ! __is_invocable( R, int, int ) );
+
+struct S { void operator()(int, ...); };
+
+SA( ! __is_invocable( S ) );
+SA(   __is_invocable( S, int ) );
+SA(   __is_invocable( S, int, int ) );
+SA(   __is_invocable( S, int, int, int ) );
+
+void fn1() {}
+
+SA(   __is_invocable( decltype(fn1) ) );
+
+void fn2(int arr[10]);
+
+SA(   __is_invocable( decltype(fn2), int[10] ) );
+SA(   __is_invocable( decltype(fn2), int(&)[10] ) );
+SA(   __is_invocable( decltype(fn2), int(&&)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*&)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*&&)[10] ) );
+SA(   __is_invocable( decltype(fn2), int[] ) );
+
+auto lambda = []() {};
+
+SA(   __is_invocable( decltype(lambda) ) );
+
+template <typename Func, typename... Args>
+struct can_invoke {
+    static constexpr bool value = __is_invocable( Func, Args... );
+};
+
+SA( can_invoke<decltype(lambda)>::value );
+
+struct T {
+  void func() const {}
+  int data;
+};
+
+SA(   __is_invocable( decltype(&T::func)&, T& ) );
+SA(   __is_invocable( decltype(&T::data)&, T& ) );
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable2.C b/gcc/testsuite/g++.dg/ext/is_invocable2.C
new file mode 100644
index 00000000000..a68aefd3e13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable2.C
@@ -0,0 +1,139 @@
+// { dg-do compile { target c++11 } }
+// __is_invocable should handle std::reference_wrapper correctly.
+
+#include <functional>
+
+#define SA(X) static_assert((X),#X)
+
+using std::reference_wrapper;
+
+using func_type_v0 = void(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_v0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_v0>, int ) );
+
+using func_type_i0 = int(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_i0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_i0>, int ) );
+
+using func_type_l0 = int&(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_l0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_l0(int)> ) );
+
+using func_type_ii = int(*)(int);
+
+SA( ! __is_invocable( reference_wrapper<func_type_ii> ) );
+SA(   __is_invocable( reference_wrapper<func_type_ii>, int ) );
+
+using func_type_il = int(*)(int&);
+
+SA( ! __is_invocable( reference_wrapper<func_type_il> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_il>, int ) );
+SA(   __is_invocable( reference_wrapper<func_type_il>, int& ) );
+
+using func_type_ir = int(*)(int&&);
+
+SA( ! __is_invocable( reference_wrapper<func_type_ir> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_ir>, int& ) );
+SA(   __is_invocable( reference_wrapper<func_type_ir>, int ) );
+SA(   __is_invocable( reference_wrapper<func_type_ir>, int&& ) );
+
+struct A { };
+
+using mem_type_i = int A::*;
+
+SA( ! __is_invocable( reference_wrapper<mem_type_i> ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int* ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int& ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int&& ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A* ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A& ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A&& ) );
+
+using memfun_type_i = int (A::*)();
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_i> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int&& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A* ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A&& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, const A& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, A&, int ) );
+
+using memfun_type_ic = int (A::*)() const;
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A&, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A*, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A&, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A*, int ) );
+
+using memfun_type_iic = int& (A::*)(int&) const;
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A&, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A&, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A*, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A*, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int&, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A*, int& ) );
+
+struct B {
+  int& operator()();
+  long& operator()() const;
+  bool& operator()(int);
+private:
+  void operator()(int, int);
+};
+using CB = const B;
+
+SA(   __is_invocable( reference_wrapper<B> ) );
+SA(   __is_invocable( reference_wrapper<B>& ) );
+SA(   __is_invocable( reference_wrapper<B>&& ) );
+SA(   __is_invocable( reference_wrapper<CB> ) );
+SA(   __is_invocable( reference_wrapper<CB>& ) );
+SA(   __is_invocable( reference_wrapper<B>, int ) );
+SA( ! __is_invocable( reference_wrapper<B>&, int, int ) );
+
+struct C : B { int& operator()() = delete; };
+using CC = const C;
+
+SA( ! __is_invocable( reference_wrapper<C> ) );
+SA( ! __is_invocable( reference_wrapper<C>& ) );
+SA( ! __is_invocable( reference_wrapper<C>&& ) );
+SA( ! __is_invocable( reference_wrapper<CC> ) );
+SA( ! __is_invocable( reference_wrapper<CC>& ) );
+
+struct D { B operator*(); };
+using CD = const D;
+
+SA( ! __is_invocable( reference_wrapper<D> ) );
+SA( ! __is_invocable( reference_wrapper<D>& ) );
+SA( ! __is_invocable( reference_wrapper<D>&& ) );
+SA( ! __is_invocable( reference_wrapper<D>* ) );
+SA( ! __is_invocable( reference_wrapper<D*> ) );
+SA( ! __is_invocable( reference_wrapper<D*>* ) );
+
+std::function<void()> fn = []() {};
+auto refwrap = std::ref(fn);
+
+SA(   __is_invocable( decltype(fn) ) );
+SA(   __is_invocable( decltype(refwrap) ) );
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable3.C b/gcc/testsuite/g++.dg/ext/is_invocable3.C
new file mode 100644
index 00000000000..e2b0c5ef406
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable3.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+// __is_invocable should handle incomplete class correctly.
+
+#define SA(X) static_assert((X),#X)
+
+struct Incomplete;
+
+SA( ! __is_invocable( Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( int, Incomplete, int ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int, Incomplete ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( Incomplete, Incomplete() ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, Incomplete(int), int ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, Incomplete(int, int), int, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( Incomplete, Incomplete(), int, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( int(Incomplete), Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int(int, Incomplete), int, Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int(int, Incomplete), Incomplete, int ) ); // { dg-error "incomplete type" }
+
+SA(   __is_invocable( int(Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(Incomplete&&), Incomplete&& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, Incomplete&&), int, Incomplete&& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&&), const Incomplete&& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&&), int, const Incomplete&& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&), const Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&), int, const Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int Incomplete::*, const Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA( ! __is_invocable( void (Incomplete::*)(long&), const Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( void (Incomplete::*)(long&) const, Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
+
+template <typename T>
+struct Holder { T t; };
+
+SA(   __is_invocable( int(Holder<Incomplete>&), Holder<Incomplete>& ) ); // { dg-bogus "incomplete type" }
+
+// Define Incomplete, which is now not incomplete.
+struct Incomplete { void operator()(); };
+
+SA( __is_invocable( Incomplete ) ); // { dg-bogus "incomplete type" }
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable4.C b/gcc/testsuite/g++.dg/ext/is_invocable4.C
new file mode 100644
index 00000000000..d1efccf08f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable4.C
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++11 } }
+// Failed access check should be a substitution failure, not an error.
+
+#define SA(X) static_assert((X),#X)
+
+template<bool B>
+struct bool_constant { static constexpr bool value = B; };
+
+template<typename _Fn, typename... _ArgTypes>
+struct is_invocable
+: public bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+{ };
+
+#if __cpp_variable_templates
+template<typename _Fn, typename... _ArgTypes>
+constexpr bool is_invocable_v = __is_invocable(_Fn, _ArgTypes...);
+#endif
+
+class Private
+{
+  void operator()() const
+  {
+    SA( ! is_invocable<Private>::value );
+#if __cpp_variable_templates
+    SA( ! is_invocable_v<Private> );
+#endif
+  }
+};
+
+SA( ! is_invocable<Private>::value );
+#if __cpp_variable_templates
+SA( ! is_invocable_v<Private> );
+#endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v23 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (31 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
@ 2023-10-20 13:53                       ` Ken Matsui
  2023-10-20 16:16                       ` [PATCH v24 00/33] Optimize type traits performance Ken Matsui
  33 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 13:53 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_invocable
by dispatching to the new __is_invocable built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_invocable): Use __is_invocable
	built-in trait.
	* testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
	the new error from __is_invocable.
	* testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits                        | 6 ++++++
 .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
 .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
 3 files changed, 8 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 75a94cb8d7e..91851b78c7e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
 
   /// std::is_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+  template<typename _Fn, typename... _ArgTypes>
+    struct is_invocable
+    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+#else
   template<typename _Fn, typename... _ArgTypes>
     struct is_invocable
     : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
+#endif
     {
       static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
 	"_Fn must be a complete class or an unbounded array");
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
index 34d1d9431d1..6db004bdc43 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
 
 #include <type_traits>
 
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
index e1e54d25ee5..608218b533c 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-error "incomplete type" "" { target *-*-* } 0 }
 
 #include <type_traits>
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v24 00/33] Optimize type traits performance
  2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
                                         ` (32 preceding siblings ...)
  2023-10-20 13:53                       ` [PATCH v23 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
@ 2023-10-20 16:16                       ` Ken Matsui
  2023-10-20 16:17                         ` [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
  33 siblings, 2 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 16:16 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits performance by implementing
built-in type traits and using them in libstdc++.

Changes in v24:

	* Fixed the way to handle an incomplete type error from __is_invocable
	in the test cases so that we can correctly test both the use of
	built-in and vice-versa.

Changes in v23:

	* Improved the comment in cp-tree.h.
	* Moved the definition of cp_traits to lex.cc from parser.cc.
	* Implemented __is_invocable built-in trait.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (33):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize std::is_const compilation performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize std::is_volatile compilation performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize std::is_unbounded_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize std::is_pointer compilation performance
  c++: Implement __is_invocable built-in trait
  libstdc++: Optimize std::is_invocable compilation performance

 gcc/c-family/c-common.cc		       |   7 -
 gcc/c-family/c-common.h		       |   5 -
 gcc/cp/constraint.cc			       | 109 ++++--
 gcc/cp/cp-objcp-common.cc		       |   8 +-
 gcc/cp/cp-trait.def			       |  25 +-
 gcc/cp/cp-tree.h			       |  32 +-
 gcc/cp/lex.cc				       |  34 ++
 gcc/cp/method.h			       |  28 ++
 gcc/cp/parser.cc			       | 118 +++---
 gcc/cp/semantics.cc			       | 284 ++++++++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 113 ++++--
 gcc/testsuite/g++.dg/ext/is_array.C	       |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++
 gcc/testsuite/g++.dg/ext/is_const.C	       |  19 +
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++
 gcc/testsuite/g++.dg/ext/is_invocable1.C      | 337 ++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable2.C      | 139 ++++++++
 gcc/testsuite/g++.dg/ext/is_invocable3.C      |  51 +++
 gcc/testsuite/g++.dg/ext/is_invocable4.C      |  33 ++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_object.C	       |  29 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C	       |  51 +++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 +
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++
 libstdc++-v3/include/bits/cpp_type_traits.h   |   8 +
 libstdc++-v3/include/std/type_traits	       | 219 +++++++++++-
 .../is_invocable/incomplete_args_neg.cc       |   1 +
 .../20_util/is_invocable/incomplete_neg.cc    |   1 +
 33 files changed, 1878 insertions(+), 196 deletions(-)
 create mode 100644 gcc/cp/method.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-20 16:16                       ` [PATCH v24 00/33] Optimize type traits performance Ken Matsui
@ 2023-10-20 16:17                         ` Ken Matsui
  2023-10-23 17:04                           ` Patrick Palka
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
  1 sibling, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 16:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_invocable
by dispatching to the new __is_invocable built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_invocable): Use __is_invocable
	built-in trait.
	* testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
	the new error from __is_invocable.
	* testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits                        | 6 ++++++
 .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
 .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
 3 files changed, 8 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 75a94cb8d7e..91851b78c7e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
 
   /// std::is_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+  template<typename _Fn, typename... _ArgTypes>
+    struct is_invocable
+    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+#else
   template<typename _Fn, typename... _ArgTypes>
     struct is_invocable
     : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
+#endif
     {
       static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
 	"_Fn must be a complete class or an unbounded array");
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
index 34d1d9431d1..3f9e5274f3c 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-prune-output "invalid use of incomplete type" }
 
 #include <type_traits>
 
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
index e1e54d25ee5..92af48c48b6 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-prune-output "invalid use of incomplete type" }
 
 #include <type_traits>
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-20 13:53                       ` [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-20 19:11                         ` Patrick Palka
  2023-10-20 20:00                           ` Ken Matsui
  2023-10-23 20:27                         ` Jason Merrill
  1 sibling, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-20 19:11 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Jason Merrill, Jonathan Wakely

On Fri, Oct 20, 2023 at 10:02 AM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>
> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in traitreviewed but can be pushed incrementally if anything
> identifiers.

Thanks a lot, patches 1-31 in this series LGTM.




>
> gcc/c-family/ChangeLog:
>
>         * c-common.cc (c_common_reswords): Remove all mappings of
>         built-in traits.
>         * c-common.h (enum rid): Remove all RID values for built-in traits.
>
> gcc/cp/ChangeLog:
>
>         * cp-objcp-common.cc (names_builtin_p): Remove all RID value
>         cases for built-in traits.  Check for built-in traits via
>         the new cik_trait kind.
>         * cp-tree.h (enum cp_trait_kind): Set its underlying type to
>         addr_space_t.
>         (struct cp_trait): New struct to hold trait information.
>         (cp_traits): New array to hold a mapping to all traits.
>         (cik_reserved_for_udlit): Rename to ...
>         (cik_trait): ... this.
>         (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
>         (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
>         * lex.cc (cp_traits): Define its values, declared in cp-tree.h.
>         (init_cp_traits): New function to set cik_trait and
>         IDENTIFIER_CP_INDEX for all built-in trait identifiers.
>         (cxx_init): Call init_cp_traits function.
>         * parser.cc (cp_lexer_lookup_trait): New function to look up a
>         built-in trait by IDENTIFIER_CP_INDEX.
>         (cp_lexer_lookup_trait_expr): Likewise, look up an
>         expression-yielding built-in trait.
>         (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
>         built-in trait.
>         (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
>         for built-in traits.
>         (cp_lexer_next_token_is_decl_specifier_keyword): Handle
>         type-yielding built-in traits.
>         (cp_parser_primary_expression): Remove all RID value cases for
>         built-in traits.  Handle expression-yielding built-in traits.
>         (cp_parser_trait): Handle cp_trait instead of enum rid.
>         (cp_parser_simple_type_specifier): Remove all RID value cases
>         for built-in traits.  Handle type-yielding built-in traits.
>
> Co-authored-by: Patrick Palka <ppalka@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/c-family/c-common.cc  |   7 ---
>  gcc/c-family/c-common.h   |   5 --
>  gcc/cp/cp-objcp-common.cc |   8 +--
>  gcc/cp/cp-tree.h          |  32 +++++++++---
>  gcc/cp/lex.cc             |  34 ++++++++++++
>  gcc/cp/parser.cc          | 105 +++++++++++++++++++++++---------------
>  6 files changed, 126 insertions(+), 65 deletions(-)
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
>    { "wchar_t",         RID_WCHAR,      D_CXXONLY },
>    { "while",           RID_WHILE,      0 },
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  { NAME,              RID_##CODE,     D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -  /* An alias for __is_same.  */
> -  { "__is_same_as",    RID_IS_SAME,    D_CXXONLY },
> -
>    /* C++ transactional memory.  */
>    { "synchronized",    RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
>    { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
>    RID_BUILTIN_LAUNDER,
>    RID_BUILTIN_BIT_CAST,
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -  RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
>    /* C++11 */
>    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
>         }
>      }
>
> +  /* Check for built-in traits.  */
> +  if (IDENTIFIER_TRAIT_P (id))
> +    return true;
> +
>    /* Also detect common reserved C++ words that aren't strictly built-in
>       functions.  */
>    switch (C_RID_CODE (id))
> @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
>      case RID_BUILTIN_ASSOC_BARRIER:
>      case RID_BUILTIN_BIT_CAST:
>      case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
>        return true;
>      default:
>        break;
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index efcd2de54e5..e62e4df4db0 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
>    cik_simple_op = 4,   /* Non-assignment operator name.  */
>    cik_assign_op = 5,   /* An assignment operator name.  */
>    cik_conv_op = 6,     /* Conversion operator name.  */
> -  cik_reserved_for_udlit = 7,  /* Not yet in use  */
> +  cik_trait = 7,       /* Built-in trait name.  */
>    cik_max
>  };
>
> @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
>      & IDENTIFIER_KIND_BIT_0 (NODE))
>
>  /* True if this identifier is for any operator name (including
> -   conversions).  Value 4, 5, 6 or 7.  */
> +   conversions).  Value 4, 5, or 6.  */
>  #define IDENTIFIER_ANY_OP_P(NODE)              \
> -  (IDENTIFIER_KIND_BIT_2 (NODE))
> +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
>
>  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
>  #define IDENTIFIER_OVL_OP_P(NODE)              \
> @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
>     & IDENTIFIER_KIND_BIT_0 (NODE))
>
>  /* True if this identifier is the name of a type-conversion
> -   operator.  Value 7.  */
> +   operator.  Value 6.  */
>  #define IDENTIFIER_CONV_OP_P(NODE)             \
>    (IDENTIFIER_ANY_OP_P (NODE)                  \
>     & IDENTIFIER_KIND_BIT_1 (NODE)              \
>     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
>
> +/* True if this identifier is the name of a built-in trait.  */
> +#define IDENTIFIER_TRAIT_P(NODE)               \
> +  (IDENTIFIER_KIND_BIT_0 (NODE)                        \
> +   && IDENTIFIER_KIND_BIT_1 (NODE)             \
> +   && IDENTIFIER_KIND_BIT_2 (NODE))
> +
>  /* True if this identifier is a new or delete operator.  */
>  #define IDENTIFIER_NEWDEL_OP_P(NODE)           \
>    (IDENTIFIER_OVL_OP_P (NODE)                  \
> @@ -1375,16 +1381,26 @@ struct GTY (()) tree_argument_pack_select {
>    int index;
>  };
>
> -/* The different kinds of traits that we encounter.  */
> -
> -enum cp_trait_kind
> -{
> +/* The different kinds of traits that we encounter.  The size is limited to
> +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> +enum cp_trait_kind : addr_space_t {
>  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
>    CPTK_##CODE,
>  #include "cp-trait.def"
>  #undef DEFTRAIT
>  };
>
> +/* The trait type.  */
> +struct cp_trait {
> +  const char *name;
> +  cp_trait_kind kind;
> +  short arity;
> +  bool type;
> +};
> +
> +/* The trait table indexed by cp_trait_kind.  */
> +extern const struct cp_trait cp_traits[];
> +
>  /* The types that we are processing.  */
>  #define TRAIT_EXPR_TYPE1(NODE) \
>    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..a939e2e5f13 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "langhooks.h"
>
>  static int interface_strcmp (const char *);
> +static void init_cp_traits (void);
>  static void init_cp_pragma (void);
>
>  static tree parse_strconst_pragma (const char *, int);
> @@ -97,6 +98,19 @@ ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
>  unsigned char ovl_op_mapping[MAX_TREE_CODES];
>  unsigned char ovl_op_alternate[OVL_OP_MAX];
>
> +/* The trait table, declared in cp-tree.h.  */
> +const cp_trait cp_traits[] =
> +{
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> +  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
> +#include "cp-trait.def"
> +#undef DEFTRAIT
> +};
> +/* The trait table cannot have more than 255 (addr_space_t) entries since
> +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> +             "cp_traits array cannot have more than 255 entries");
> +
>  /* Get the name of the kind of identifier T.  */
>
>  const char *
> @@ -283,6 +297,25 @@ init_reswords (void)
>      }
>  }
>
> +/* Initialize the C++ traits.  */
> +static void
> +init_cp_traits (void)
> +{
> +  tree id;
> +
> +  for (unsigned int i = 0; i < ARRAY_SIZE (cp_traits); ++i)
> +    {
> +      id = get_identifier (cp_traits[i].name);
> +      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
> +      set_identifier_kind (id, cik_trait);
> +    }
> +
> +  /* An alias for __is_same.  */
> +  id = get_identifier ("__is_same_as");
> +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> +  set_identifier_kind (id, cik_trait);
> +}
> +
>  static void
>  init_cp_pragma (void)
>  {
> @@ -324,6 +357,7 @@ cxx_init (void)
>    input_location = BUILTINS_LOCATION;
>
>    init_reswords ();
> +  init_cp_traits ();
>    init_tree ();
>    init_cp_semantics ();
>    init_operators ();
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 59b9852895e..f87d4c0a855 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
>  static void cp_lexer_stop_debugging
>    (cp_lexer *) ATTRIBUTE_UNUSED;
> +static const cp_trait *cp_lexer_lookup_trait
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_expr
> +  (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_type
> +  (const cp_token *);
>
>  static cp_token_cache *cp_token_cache_new
>    (cp_token *, cp_token *);
> @@ -1167,12 +1173,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      case RID_CONSTEVAL:
>        return true;
>
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      return true;
> -
>      default:
>        if (keyword >= RID_FIRST_INT_N
>           && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> @@ -1182,6 +1182,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>      }
>  }
>
> +/* Look ups the corresponding built-in trait if a given token is
> +   a built-in trait.  Otherwise, returns nullptr.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait (const cp_token *token)
> +{
> +  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
> +    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is an expression-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_expr (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && !trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
> +/* Similarly, but only if the token is a type-yielding
> +   built-in trait.  */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_type (const cp_token *token)
> +{
> +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> +  if (trait && trait->type)
> +    return trait;
> +
> +  return nullptr;
> +}
> +
>  /* Return true if the next token is a keyword for a decl-specifier.  */
>
>  static bool
> @@ -1190,6 +1228,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
>    cp_token *token;
>
>    token = cp_lexer_peek_token (lexer);
> +  if (cp_lexer_lookup_trait_type (token))
> +    return true;
>    return cp_keyword_starts_decl_specifier_p (token->keyword);
>  }
>
> @@ -2854,7 +2894,7 @@ static void cp_parser_late_parsing_default_args
>  static tree cp_parser_sizeof_operand
>    (cp_parser *, enum rid);
>  static cp_expr cp_parser_trait
> -  (cp_parser *, enum rid);
> +  (cp_parser *, const cp_trait *);
>  static bool cp_parser_declares_only_class_p
>    (cp_parser *);
>  static void cp_parser_set_storage_class
> @@ -6029,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
>         case RID_OFFSETOF:
>           return cp_parser_builtin_offsetof (parser);
>
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> -       case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> -         return cp_parser_trait (parser, token->keyword);
> -
>         // C++ concepts
>         case RID_REQUIRES:
>           return cp_parser_requires_expression (parser);
> @@ -6073,6 +6107,9 @@ cp_parser_primary_expression (cp_parser *parser,
>          `::' as the beginning of a qualified-id, or the "operator"
>          keyword.  */
>      case CPP_NAME:
> +      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
> +       return cp_parser_trait (parser, trait);
> +      /* FALLTHRU */
>      case CPP_SCOPE:
>      case CPP_TEMPLATE_ID:
>      case CPP_NESTED_NAME_SPECIFIER:
> @@ -11041,28 +11078,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
>  /* Parse a builtin trait expression or type.  */
>
>  static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
>  {
> -  cp_trait_kind kind;
> +  const cp_trait_kind kind = trait->kind;
>    tree type1, type2 = NULL_TREE;
> -  bool binary = false;
> -  bool variadic = false;
> -  bool type = false;
> -
> -  switch (keyword)
> -    {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> -    case RID_##CODE:                    \
> -      kind = CPTK_##CODE;               \
> -      binary = (ARITY == 2);            \
> -      variadic = (ARITY == -1);                 \
> -      type = (TCC == tcc_type);                 \
> -      break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> -    default:
> -      gcc_unreachable ();
> -    }
> +  const bool binary = (trait->arity == 2);
> +  const bool variadic = (trait->arity == -1);
> +  const bool type = trait->type;
>
>    /* Get location of initial token.  */
>    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -20089,20 +20111,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>
>        return type;
>
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> -    case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> -      type = cp_parser_trait (parser, token->keyword);
> +    default:
> +      break;
> +    }
> +
> +  /* If token is a type-yielding built-in traits, parse it.  */
> +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> +  if (trait)
> +    {
> +      type = cp_parser_trait (parser, trait);
>        if (decl_specs)
>         cp_parser_set_decl_spec_type (decl_specs, type,
>                                       token,
>                                       /*type_definition_p=*/false);
>
>        return type;
> -
> -    default:
> -      break;
>      }
>
>    /* If token is an already-parsed decltype not followed by ::,
> --
> 2.42.0
>


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-20 19:11                         ` Patrick Palka
@ 2023-10-20 20:00                           ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-20 20:00 UTC (permalink / raw)
  To: Patrick Palka
  Cc: Ken Matsui, gcc-patches, libstdc++, Jason Merrill, Jonathan Wakely

On Fri, Oct 20, 2023 at 12:12 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Fri, Oct 20, 2023 at 10:02 AM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
> >
> > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > once in a C++ translation unit, this patch removes all RID values for built-in
> > traits and uses the identifier node to look up the specific trait.  Rather
> > than holding traits as keywords, we set all trait identifiers as cik_trait,
> > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > identifier so that we accept the use of non-function-like built-in traitreviewed but can be pushed incrementally if anything
> > identifiers.
>
> Thanks a lot, patches 1-31 in this series LGTM.
>

Thank you!!!

>
>
>
> >
> > gcc/c-family/ChangeLog:
> >
> >         * c-common.cc (c_common_reswords): Remove all mappings of
> >         built-in traits.
> >         * c-common.h (enum rid): Remove all RID values for built-in traits.
> >
> > gcc/cp/ChangeLog:
> >
> >         * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> >         cases for built-in traits.  Check for built-in traits via
> >         the new cik_trait kind.
> >         * cp-tree.h (enum cp_trait_kind): Set its underlying type to
> >         addr_space_t.
> >         (struct cp_trait): New struct to hold trait information.
> >         (cp_traits): New array to hold a mapping to all traits.
> >         (cik_reserved_for_udlit): Rename to ...
> >         (cik_trait): ... this.
> >         (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> >         (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> >         * lex.cc (cp_traits): Define its values, declared in cp-tree.h.
> >         (init_cp_traits): New function to set cik_trait and
> >         IDENTIFIER_CP_INDEX for all built-in trait identifiers.
> >         (cxx_init): Call init_cp_traits function.
> >         * parser.cc (cp_lexer_lookup_trait): New function to look up a
> >         built-in trait by IDENTIFIER_CP_INDEX.
> >         (cp_lexer_lookup_trait_expr): Likewise, look up an
> >         expression-yielding built-in trait.
> >         (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> >         built-in trait.
> >         (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> >         for built-in traits.
> >         (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> >         type-yielding built-in traits.
> >         (cp_parser_primary_expression): Remove all RID value cases for
> >         built-in traits.  Handle expression-yielding built-in traits.
> >         (cp_parser_trait): Handle cp_trait instead of enum rid.
> >         (cp_parser_simple_type_specifier): Remove all RID value cases
> >         for built-in traits.  Handle type-yielding built-in traits.
> >
> > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/c-family/c-common.cc  |   7 ---
> >  gcc/c-family/c-common.h   |   5 --
> >  gcc/cp/cp-objcp-common.cc |   8 +--
> >  gcc/cp/cp-tree.h          |  32 +++++++++---
> >  gcc/cp/lex.cc             |  34 ++++++++++++
> >  gcc/cp/parser.cc          | 105 +++++++++++++++++++++++---------------
> >  6 files changed, 126 insertions(+), 65 deletions(-)
> >
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index f044db5b797..21fd333ef57 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
> > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> >    { "wchar_t",         RID_WCHAR,      D_CXXONLY },
> >    { "while",           RID_WHILE,      0 },
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  { NAME,              RID_##CODE,     D_CXXONLY },
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -  /* An alias for __is_same.  */
> > -  { "__is_same_as",    RID_IS_SAME,    D_CXXONLY },
> > -
> >    /* C++ transactional memory.  */
> >    { "synchronized",    RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> >    { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 1fdba7ef3ea..051a442e0f4 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -168,11 +168,6 @@ enum rid
> >    RID_BUILTIN_LAUNDER,
> >    RID_BUILTIN_BIT_CAST,
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -  RID_##CODE,
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -
> >    /* C++11 */
> >    RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> >
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 93b027b80ce..b1adacfec07 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> >         }
> >      }
> >
> > +  /* Check for built-in traits.  */
> > +  if (IDENTIFIER_TRAIT_P (id))
> > +    return true;
> > +
> >    /* Also detect common reserved C++ words that aren't strictly built-in
> >       functions.  */
> >    switch (C_RID_CODE (id))
> > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> >      case RID_BUILTIN_ASSOC_BARRIER:
> >      case RID_BUILTIN_BIT_CAST:
> >      case RID_OFFSETOF:
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> >        return true;
> >      default:
> >        break;
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index efcd2de54e5..e62e4df4db0 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> >    cik_simple_op = 4,   /* Non-assignment operator name.  */
> >    cik_assign_op = 5,   /* An assignment operator name.  */
> >    cik_conv_op = 6,     /* Conversion operator name.  */
> > -  cik_reserved_for_udlit = 7,  /* Not yet in use  */
> > +  cik_trait = 7,       /* Built-in trait name.  */
> >    cik_max
> >  };
> >
> > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> >      & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is for any operator name (including
> > -   conversions).  Value 4, 5, 6 or 7.  */
> > +   conversions).  Value 4, 5, or 6.  */
> >  #define IDENTIFIER_ANY_OP_P(NODE)              \
> > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> >
> >  /* True if this identifier is for an overloaded operator. Values 4, 5.  */
> >  #define IDENTIFIER_OVL_OP_P(NODE)              \
> > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> >     & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> >  /* True if this identifier is the name of a type-conversion
> > -   operator.  Value 7.  */
> > +   operator.  Value 6.  */
> >  #define IDENTIFIER_CONV_OP_P(NODE)             \
> >    (IDENTIFIER_ANY_OP_P (NODE)                  \
> >     & IDENTIFIER_KIND_BIT_1 (NODE)              \
> >     & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> >
> > +/* True if this identifier is the name of a built-in trait.  */
> > +#define IDENTIFIER_TRAIT_P(NODE)               \
> > +  (IDENTIFIER_KIND_BIT_0 (NODE)                        \
> > +   && IDENTIFIER_KIND_BIT_1 (NODE)             \
> > +   && IDENTIFIER_KIND_BIT_2 (NODE))
> > +
> >  /* True if this identifier is a new or delete operator.  */
> >  #define IDENTIFIER_NEWDEL_OP_P(NODE)           \
> >    (IDENTIFIER_OVL_OP_P (NODE)                  \
> > @@ -1375,16 +1381,26 @@ struct GTY (()) tree_argument_pack_select {
> >    int index;
> >  };
> >
> > -/* The different kinds of traits that we encounter.  */
> > -
> > -enum cp_trait_kind
> > -{
> > +/* The different kinds of traits that we encounter.  The size is limited to
> > +   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
> > +enum cp_trait_kind : addr_space_t {
> >  #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> >    CPTK_##CODE,
> >  #include "cp-trait.def"
> >  #undef DEFTRAIT
> >  };
> >
> > +/* The trait type.  */
> > +struct cp_trait {
> > +  const char *name;
> > +  cp_trait_kind kind;
> > +  short arity;
> > +  bool type;
> > +};
> > +
> > +/* The trait table indexed by cp_trait_kind.  */
> > +extern const struct cp_trait cp_traits[];
> > +
> >  /* The types that we are processing.  */
> >  #define TRAIT_EXPR_TYPE1(NODE) \
> >    (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
> > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > index 64bcfb18196..a939e2e5f13 100644
> > --- a/gcc/cp/lex.cc
> > +++ b/gcc/cp/lex.cc
> > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "langhooks.h"
> >
> >  static int interface_strcmp (const char *);
> > +static void init_cp_traits (void);
> >  static void init_cp_pragma (void);
> >
> >  static tree parse_strconst_pragma (const char *, int);
> > @@ -97,6 +98,19 @@ ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
> >  unsigned char ovl_op_mapping[MAX_TREE_CODES];
> >  unsigned char ovl_op_alternate[OVL_OP_MAX];
> >
> > +/* The trait table, declared in cp-tree.h.  */
> > +const cp_trait cp_traits[] =
> > +{
> > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > +  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
> > +#include "cp-trait.def"
> > +#undef DEFTRAIT
> > +};
> > +/* The trait table cannot have more than 255 (addr_space_t) entries since
> > +   the index is retrieved through IDENTIFIER_CP_INDEX.  */
> > +static_assert(ARRAY_SIZE (cp_traits) <= 255,
> > +             "cp_traits array cannot have more than 255 entries");
> > +
> >  /* Get the name of the kind of identifier T.  */
> >
> >  const char *
> > @@ -283,6 +297,25 @@ init_reswords (void)
> >      }
> >  }
> >
> > +/* Initialize the C++ traits.  */
> > +static void
> > +init_cp_traits (void)
> > +{
> > +  tree id;
> > +
> > +  for (unsigned int i = 0; i < ARRAY_SIZE (cp_traits); ++i)
> > +    {
> > +      id = get_identifier (cp_traits[i].name);
> > +      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
> > +      set_identifier_kind (id, cik_trait);
> > +    }
> > +
> > +  /* An alias for __is_same.  */
> > +  id = get_identifier ("__is_same_as");
> > +  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
> > +  set_identifier_kind (id, cik_trait);
> > +}
> > +
> >  static void
> >  init_cp_pragma (void)
> >  {
> > @@ -324,6 +357,7 @@ cxx_init (void)
> >    input_location = BUILTINS_LOCATION;
> >
> >    init_reswords ();
> > +  init_cp_traits ();
> >    init_tree ();
> >    init_cp_semantics ();
> >    init_operators ();
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index 59b9852895e..f87d4c0a855 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> >  static void cp_lexer_stop_debugging
> >    (cp_lexer *) ATTRIBUTE_UNUSED;
> > +static const cp_trait *cp_lexer_lookup_trait
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_expr
> > +  (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_type
> > +  (const cp_token *);
> >
> >  static cp_token_cache *cp_token_cache_new
> >    (cp_token *, cp_token *);
> > @@ -1167,12 +1173,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      case RID_CONSTEVAL:
> >        return true;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      return true;
> > -
> >      default:
> >        if (keyword >= RID_FIRST_INT_N
> >           && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > @@ -1182,6 +1182,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> >      }
> >  }
> >
> > +/* Look ups the corresponding built-in trait if a given token is
> > +   a built-in trait.  Otherwise, returns nullptr.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait (const cp_token *token)
> > +{
> > +  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
> > +    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
> > +
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is an expression-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && !trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is a type-yielding
> > +   built-in trait.  */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_type (const cp_token *token)
> > +{
> > +  const cp_trait *trait = cp_lexer_lookup_trait (token);
> > +  if (trait && trait->type)
> > +    return trait;
> > +
> > +  return nullptr;
> > +}
> > +
> >  /* Return true if the next token is a keyword for a decl-specifier.  */
> >
> >  static bool
> > @@ -1190,6 +1228,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> >    cp_token *token;
> >
> >    token = cp_lexer_peek_token (lexer);
> > +  if (cp_lexer_lookup_trait_type (token))
> > +    return true;
> >    return cp_keyword_starts_decl_specifier_p (token->keyword);
> >  }
> >
> > @@ -2854,7 +2894,7 @@ static void cp_parser_late_parsing_default_args
> >  static tree cp_parser_sizeof_operand
> >    (cp_parser *, enum rid);
> >  static cp_expr cp_parser_trait
> > -  (cp_parser *, enum rid);
> > +  (cp_parser *, const cp_trait *);
> >  static bool cp_parser_declares_only_class_p
> >    (cp_parser *);
> >  static void cp_parser_set_storage_class
> > @@ -6029,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> >         case RID_OFFSETOF:
> >           return cp_parser_builtin_offsetof (parser);
> >
> > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > -       case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_EXPR
> > -         return cp_parser_trait (parser, token->keyword);
> > -
> >         // C++ concepts
> >         case RID_REQUIRES:
> >           return cp_parser_requires_expression (parser);
> > @@ -6073,6 +6107,9 @@ cp_parser_primary_expression (cp_parser *parser,
> >          `::' as the beginning of a qualified-id, or the "operator"
> >          keyword.  */
> >      case CPP_NAME:
> > +      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
> > +       return cp_parser_trait (parser, trait);
> > +      /* FALLTHRU */
> >      case CPP_SCOPE:
> >      case CPP_TEMPLATE_ID:
> >      case CPP_NESTED_NAME_SPECIFIER:
> > @@ -11041,28 +11078,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> >  /* Parse a builtin trait expression or type.  */
> >
> >  static cp_expr
> > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> >  {
> > -  cp_trait_kind kind;
> > +  const cp_trait_kind kind = trait->kind;
> >    tree type1, type2 = NULL_TREE;
> > -  bool binary = false;
> > -  bool variadic = false;
> > -  bool type = false;
> > -
> > -  switch (keyword)
> > -    {
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > -    case RID_##CODE:                    \
> > -      kind = CPTK_##CODE;               \
> > -      binary = (ARITY == 2);            \
> > -      variadic = (ARITY == -1);                 \
> > -      type = (TCC == tcc_type);                 \
> > -      break;
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > -    default:
> > -      gcc_unreachable ();
> > -    }
> > +  const bool binary = (trait->arity == 2);
> > +  const bool variadic = (trait->arity == -1);
> > +  const bool type = trait->type;
> >
> >    /* Get location of initial token.  */
> >    location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > @@ -20089,20 +20111,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> >
> >        return type;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > -    case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > -      type = cp_parser_trait (parser, token->keyword);
> > +    default:
> > +      break;
> > +    }
> > +
> > +  /* If token is a type-yielding built-in traits, parse it.  */
> > +  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > +  if (trait)
> > +    {
> > +      type = cp_parser_trait (parser, trait);
> >        if (decl_specs)
> >         cp_parser_set_decl_spec_type (decl_specs, type,
> >                                       token,
> >                                       /*type_definition_p=*/false);
> >
> >        return type;
> > -
> > -    default:
> > -      break;
> >      }
> >
> >    /* If token is an already-parsed decltype not followed by ::,
> > --
> > 2.42.0
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-20 13:53                       ` [PATCH v23 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
@ 2023-10-20 21:29                         ` Patrick Palka
  2023-10-20 21:31                           ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-20 21:29 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Fri, 20 Oct 2023, Ken Matsui wrote:

> This patch implements built-in trait for std::is_invocable.

Nice!  My email client unfortunately ate my first review attempt, so
apologies for my brevity this time around.

> gcc/cp/ChangeLog:
> 
> 	* cp-trait.def: Define __is_invocable.
> 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
> 	* semantics.cc (trait_expr_value): Likewise.
> 	(finish_trait_expr): Likewise.
> 	(is_invocable_p): New function.
> 	* method.h: New file to export build_trait_object in method.cc.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
> 	* g++.dg/ext/is_invocable1.C: New test.
> 	* g++.dg/ext/is_invocable2.C: New test.
> 	* g++.dg/ext/is_invocable3.C: New test.
> 	* g++.dg/ext/is_invocable4.C: New test.
> 
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  gcc/cp/constraint.cc                     |   6 +
>  gcc/cp/cp-trait.def                      |   1 +
>  gcc/cp/method.h                          |  28 ++
>  gcc/cp/semantics.cc                      | 135 +++++++++
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
>  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++++++++++++++++++++++
>  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 ++++++++++
>  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 ++++
>  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
>  9 files changed, 733 insertions(+)
>  create mode 100644 gcc/cp/method.h
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 9fce36e12d1..29bf548d30a 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3754,6 +3754,12 @@ diagnose_trait_expr (tree expr, tree args)
>      case CPTK_IS_FUNCTION:
>        inform (loc, "  %qT is not a function", t1);
>        break;
> +    case CPTK_IS_INVOCABLE:
> +      if (!t2)
> +    inform (loc, "  %qT is not invocable", t1);
> +      else
> +    inform (loc, "  %qT is not invocable by %qE", t1, t2);
> +      break;
>      case CPTK_IS_LAYOUT_COMPATIBLE:
>        inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
>        break;
> diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> index 05514a51c21..b8b7608c122 100644
> --- a/gcc/cp/cp-trait.def
> +++ b/gcc/cp/cp-trait.def
> @@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
>  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
>  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
>  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> +DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
>  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
>  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
>  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
> diff --git a/gcc/cp/method.h b/gcc/cp/method.h
> new file mode 100644
> index 00000000000..1aec8ec5cfd
> --- /dev/null
> +++ b/gcc/cp/method.h
> @@ -0,0 +1,28 @@
> +/* Functions exported by method.cc.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GCC_CP_METHOD_H
> +#define GCC_CP_METHOD_H 1
> +
> +#include "tree.h"
> +
> +/* In method.cc  */
> +extern tree build_trait_object (tree type);

Since other method.cc exports are already declared in cp-tree.h, for now
let's just declare this in cp-tree.h as well (under build_stub_object)
instead of creating a new header file.

> +
> +#endif  /* GCC_CP_METHOD_H  */
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 7cccbae5287..cc2e400531a 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gomp-constants.h"
>  #include "predict.h"
>  #include "memmodel.h"
> +#include "method.h"
> +
> +#include "print-tree.h"
> +#include "tree-pretty-print.h"
>  
>  /* There routines provide a modular interface to perform many parsing
>     operations.  They may therefore be used during actual parsing, or
> @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
>    return saw_copy;
>  }
>  
> +/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
> +
> +static bool
> +is_invocable_p (tree fn_type, tree arg_types)
> +{
> +  /* ARG_TYPES must be a TREE_VEC.  */
> +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
> +
> +  /* Access check is required to determine if the given is invocable.  */
> +  deferring_access_check_sentinel acs (dk_no_deferred);
> +
> +  /* std::is_invocable is an unevaluated context.  */
> +  cp_unevaluated cp_uneval_guard;
> +
> +  bool is_ptrdatamem;
> +  bool is_ptrmemfunc;
> +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
> +    {
> +      tree deref_fn_type = TREE_TYPE (fn_type);
> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
> +
> +      /* Dereference fn_type if it is a pointer to member.  */
> +      if (is_ptrdatamem || is_ptrmemfunc)
> +	fn_type = deref_fn_type;
> +    }
> +  else
> +    {
> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
> +    }
> +
> +  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
> +    /* A pointer to data member with non-one argument is not invocable.  */
> +    return false;
> +
> +  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
> +    /* A pointer to member function with no arguments is not invocable.  */
> +    return false;
> +
> +  /* Construct an expression of a pointer to member.  */
> +  tree datum;
> +  if (is_ptrdatamem || is_ptrmemfunc)
> +    {
> +      tree datum_type = TREE_VEC_ELT (arg_types, 0);
> +
> +      /* Dereference datum.  */
> +      if (CLASS_TYPE_P (datum_type))
> +	{
> +	  bool is_refwrap = false;
> +
> +	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
> +	  if (decl_in_std_namespace_p (datum_decl))
> +	    {
> +	      tree name = DECL_NAME (datum_decl);
> +	      if (name && (id_equal (name, "reference_wrapper")))
> +		{
> +		  /* Handle std::reference_wrapper.  */
> +		  is_refwrap = true;
> +		  datum_type = cp_build_reference_type (datum_type, false);
> +		}
> +	    }
> +
> +	  datum = build_trait_object (datum_type);
> +
> +	  /* If datum_type was not std::reference_wrapper, check if it has
> +	     operator*() overload.  If datum_type was std::reference_wrapper,
> +	     avoid dereferencing the datum twice.  */
> +	  if (!is_refwrap)
> +	    if (get_class_binding (datum_type, get_identifier ("operator*")))

We probably should use lookup_member instead of get_class_binding since
IIUC the latter doesn't look into bases:

  struct A { int m; };
  struct B { A& operator*(): };
  struct C : B { };
  static_assert(std::is_invocable_v<int A::*, C>);

However, I notice that the specification of INVOKE
(https://eel.is/c++draft/func.require#lib:INVOKE) doesn't mention name
lookup at all so it strikes me as suspicious that we'd perform name
lookup here.  I think this would misbehave for:

  struct A { };
  struct B : A { A& operator*() = delete; };
  static_assert(std::is_invocable_v<int A::*, B>);

  struct C : private A { A& operator*(); };
  static_assert(std::is_invocable_v<int A::*, C>);

ultimately because we end up choosing the dereference form of INVOKE,
but according to 1.1/1.4 we should choose the non-dereference form?

> +	      /* Handle operator*().  */
> +	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
> +					    RO_UNARY_STAR, NULL_TREE,
> +					    tf_none);
> +	}
> +      else if (POINTER_TYPE_P (datum_type))
> +	datum = build_trait_object (TREE_TYPE (datum_type));
> +      else
> +	datum = build_trait_object (datum_type);
> +    }
> +
> +  /* Build a function expression.  */
> +  tree fn;
> +  if (is_ptrdatamem)
> +    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);

Maybe exit early for the is_ptrdatamem case here (and simplify the rest
of the function accordingly)?

> +  else if (is_ptrmemfunc)
> +    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
> +  else
> +    fn = build_trait_object (fn_type);
> +
> +  /* Construct arguments to the function and an expression of a call.  */
> +  if (!is_ptrdatamem)
> +    {
> +      releasing_vec args;
> +
> +      if (is_ptrmemfunc)
> +	{
> +	  /* A pointer to member function is internally converted to a pointer
> +	     to function that takes a pointer to the dereferenced datum type
> +	     as its first argument and original arguments afterward.  If the
> +	     function is a const member function, the first argument also
> +	     requires a const datum pointer and vice-versa.  */
> +
> +	  tree datum_type = TREE_TYPE (datum);
> +	  if (TYPE_REF_P (datum_type))
> +	    datum_type = TREE_TYPE (datum_type);
> +
> +	  datum = build_trait_object (build_pointer_type (datum_type));
> +	  vec_safe_push (args, datum);
> +	}
> +
> +      for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
> +	{
> +	  tree arg_type = TREE_VEC_ELT (arg_types, i);
> +	  tree arg = build_trait_object (arg_type);
> +	  vec_safe_push (args, arg);
> +	}
> +
> +      fn = finish_call_expr (fn, &args, false, false, tf_none);
> +    }
> +
> +  if (error_operand_p (fn))
> +    return false;
> +
> +  return true;
> +}
> +
>  /* Return true if DERIVED is pointer interconvertible base of BASE.  */
>  
>  static bool
> @@ -12181,6 +12312,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
>      case CPTK_IS_FUNCTION:
>        return type_code1 == FUNCTION_TYPE;
>  
> +    case CPTK_IS_INVOCABLE:
> +      return is_invocable_p (type1, type2);
> +
>      case CPTK_IS_LAYOUT_COMPATIBLE:
>        return layout_compatible_type_p (type1, type2);
>  
> @@ -12390,6 +12524,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
>        break;
>  
>      case CPTK_IS_CONVERTIBLE:
> +    case CPTK_IS_INVOCABLE:
>      case CPTK_IS_NOTHROW_ASSIGNABLE:
>      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
>      case CPTK_IS_NOTHROW_CONVERTIBLE:
> diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> index b1430e9bd8b..3a9bda1ee03 100644
> --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> @@ -92,6 +92,9 @@
>  #if !__has_builtin (__is_function)
>  # error "__has_builtin (__is_function) failed"
>  #endif
> +#if !__has_builtin (__is_invocable)
> +# error "__has_builtin (__is_invocable) failed"
> +#endif
>  #if !__has_builtin (__is_layout_compatible)
>  # error "__has_builtin (__is_layout_compatible) failed"
>  #endif
> diff --git a/gcc/testsuite/g++.dg/ext/is_invocable1.C b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> new file mode 100644
> index 00000000000..2fd3906b571
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> @@ -0,0 +1,337 @@
> +// { dg-do compile { target c++11 } }
> +
> +#define SA(X) static_assert((X),#X)
> +
> +using func_type_v0 = void(*)();
> +
> +SA(   __is_invocable( func_type_v0 ) );
> +SA( ! __is_invocable( func_type_v0, int ) );
> +
> +using func_type_i0 = int(*)();
> +
> +SA(   __is_invocable( func_type_i0 ) );
> +SA( ! __is_invocable( func_type_i0, int ) );
> +
> +using func_type_l0 = int&(*)();
> +
> +SA(   __is_invocable( func_type_l0 ) );
> +SA( ! __is_invocable( func_type_l0(int) ) );
> +
> +using func_type_ii = int(*)(int);
> +
> +SA( ! __is_invocable( func_type_ii ) );
> +SA(   __is_invocable( func_type_ii, int ) );
> +
> +using func_type_il = int(*)(int&);
> +
> +SA( ! __is_invocable( func_type_il ) );
> +SA( ! __is_invocable( func_type_il, int ) );
> +SA(   __is_invocable( func_type_il, int& ) );
> +
> +using func_type_ir = int(*)(int&&);
> +
> +SA( ! __is_invocable( func_type_ir ) );
> +SA( ! __is_invocable( func_type_ir, int& ) );
> +SA(   __is_invocable( func_type_ir, int ) );
> +SA(   __is_invocable( func_type_ir, int&& ) );
> +
> +struct A { };
> +
> +using mem_type_i = int A::*;
> +
> +SA( ! __is_invocable( mem_type_i ) );
> +SA( ! __is_invocable( mem_type_i, int ) );
> +SA( ! __is_invocable( mem_type_i, int* ) );
> +SA( ! __is_invocable( mem_type_i, int& ) );
> +SA( ! __is_invocable( mem_type_i, int&& ) );
> +SA(   __is_invocable( mem_type_i, A ) );
> +SA(   __is_invocable( mem_type_i, A* ) );
> +SA(   __is_invocable( mem_type_i, A& ) );
> +SA(   __is_invocable( mem_type_i, A&& ) );
> +SA(   __is_invocable( mem_type_i, const A& ) );
> +SA( ! __is_invocable( mem_type_i, A&, int ) );
> +
> +using memfun_type_i = int (A::*)();
> +
> +SA( ! __is_invocable( memfun_type_i ) );
> +SA( ! __is_invocable( memfun_type_i, int ) );
> +SA( ! __is_invocable( memfun_type_i, int* ) );
> +SA( ! __is_invocable( memfun_type_i, int& ) );
> +SA( ! __is_invocable( memfun_type_i, int&& ) );
> +SA(   __is_invocable( memfun_type_i, A ) );
> +SA(   __is_invocable( memfun_type_i, A* ) );
> +SA(   __is_invocable( memfun_type_i, A& ) );
> +SA(   __is_invocable( memfun_type_i, A&& ) );
> +SA( ! __is_invocable( memfun_type_i, const A& ) );
> +SA( ! __is_invocable( memfun_type_i, A&, int ) );
> +
> +using memfun_type_ic = int (A::*)() const;
> +
> +SA( ! __is_invocable( memfun_type_ic ) );
> +SA( ! __is_invocable( memfun_type_ic, int ) );
> +SA( ! __is_invocable( memfun_type_ic, int& ) );
> +SA(   __is_invocable( memfun_type_ic, A& ) );
> +SA(   __is_invocable( memfun_type_ic, A* ) );
> +SA( ! __is_invocable( memfun_type_ic, A&, int ) );
> +SA( ! __is_invocable( memfun_type_ic, A*, int& ) );
> +SA(   __is_invocable( memfun_type_ic, const A& ) );
> +SA(   __is_invocable( memfun_type_ic, const A* ) );
> +SA( ! __is_invocable( memfun_type_ic, const A&, int& ) );
> +SA( ! __is_invocable( memfun_type_ic, const A*, int ) );
> +
> +using memfun_type_iic = int& (A::*)(int&) const;
> +
> +SA( ! __is_invocable( memfun_type_iic ) );
> +SA( ! __is_invocable( memfun_type_iic, int ) );
> +SA( ! __is_invocable( memfun_type_iic, int& ) );
> +SA( ! __is_invocable( memfun_type_iic, A&, int ) );
> +SA(   __is_invocable( memfun_type_iic, A&, int& ) );
> +SA( ! __is_invocable( memfun_type_iic, A*, int ) );
> +SA(   __is_invocable( memfun_type_iic, A*, int& ) );
> +SA( ! __is_invocable( memfun_type_iic, const A&, int ) );
> +SA( ! __is_invocable( memfun_type_iic, const A&, int&, int ) );
> +SA(   __is_invocable( memfun_type_iic, const A&, int& ) );
> +SA(   __is_invocable( memfun_type_iic, const A*, int& ) );
> +
> +struct B {
> +  int& operator()();
> +  long& operator()() const;
> +  bool& operator()(int);
> +private:
> +  void operator()(int, int);
> +};
> +using CB = const B;
> +
> +SA(   __is_invocable( B ) );
> +SA(   __is_invocable( B& ) );
> +SA(   __is_invocable( B&& ) );
> +SA( ! __is_invocable( B* ) );
> +SA(   __is_invocable( CB ) );
> +SA(   __is_invocable( CB& ) );
> +SA( ! __is_invocable( CB* ) );
> +
> +SA(   __is_invocable( B, int ) );
> +SA(   __is_invocable( B&, int ) );
> +SA(   __is_invocable( B&&, int ) );
> +SA( ! __is_invocable( B*, int ) );
> +SA( ! __is_invocable( CB, int ) );
> +SA( ! __is_invocable( CB&, int ) );
> +SA( ! __is_invocable( CB*, int ) );
> +
> +SA( ! __is_invocable( B, int, int ) );
> +SA( ! __is_invocable( B&, int, int ) );
> +SA( ! __is_invocable( B&&, int, int ) );
> +SA( ! __is_invocable( B*, int, int ) );
> +SA( ! __is_invocable( CB, int, int ) );
> +SA( ! __is_invocable( CB&, int, int ) );
> +SA( ! __is_invocable( CB*, int, int ) );
> +
> +struct C : B { int& operator()() = delete; };
> +using CC = const C;
> +
> +SA( ! __is_invocable( C ) );
> +SA( ! __is_invocable( C& ) );
> +SA( ! __is_invocable( C&& ) );
> +SA( ! __is_invocable( C* ) );
> +SA( ! __is_invocable( CC ) );
> +SA( ! __is_invocable( CC& ) );
> +SA( ! __is_invocable( CC* ) );
> +
> +struct D { B operator*(); };
> +using CD = const D;
> +
> +SA( ! __is_invocable( D ) );
> +
> +struct E { void v(); };
> +using CE = const E;
> +
> +SA( ! __is_invocable( E ) );
> +SA( ! __is_invocable( void (E::*)() ) );
> +SA(   __is_invocable( void (E::*)(), E ) );
> +SA(   __is_invocable( void (E::*)(), E* ) );
> +SA( ! __is_invocable( void (E::*)(), CE ) );
> +
> +struct F : E {};
> +using CF = const F;
> +
> +SA( ! __is_invocable( F ) );
> +SA(   __is_invocable( void (E::*)(), F ) );
> +SA(   __is_invocable( void (E::*)(), F* ) );
> +SA( ! __is_invocable( void (E::*)(), CF ) );
> +
> +struct G { E operator*(); };
> +using CG = const G;
> +
> +SA( ! __is_invocable( G ) );
> +SA(   __is_invocable( void (E::*)(), G ) );
> +SA( ! __is_invocable( void (E::*)(), G* ) );
> +SA( ! __is_invocable( void (E::*)(), CG ) );
> +
> +struct H { E& operator*(); };
> +using CH = const H;
> +
> +SA( ! __is_invocable( H ) );
> +SA(   __is_invocable( void (E::*)(), H ) );
> +SA( ! __is_invocable( void (E::*)(), H* ) );
> +SA( ! __is_invocable( void (E::*)(), CH ) );
> +
> +struct I { E&& operator*(); };
> +using CI = const I;
> +
> +SA( ! __is_invocable( I ) );
> +SA(   __is_invocable( void (E::*)(), I ) );
> +SA( ! __is_invocable( void (E::*)(), I* ) );
> +SA( ! __is_invocable( void (E::*)(), CI ) );
> +
> +struct K { E* operator*(); };
> +using CK = const K;
> +
> +SA( ! __is_invocable( K ) );
> +SA( ! __is_invocable( void (E::*)(), K ) );
> +SA( ! __is_invocable( void (E::*)(), K* ) );
> +SA( ! __is_invocable( void (E::*)(), CK ) );
> +
> +struct L { CE operator*(); };
> +using CL = const L;
> +
> +SA( ! __is_invocable( L ) );
> +SA( ! __is_invocable( void (E::*)(), L ) );
> +SA( ! __is_invocable( void (E::*)(), L* ) );
> +SA( ! __is_invocable( void (E::*)(), CL ) );
> +
> +struct M {
> +  int i;
> +private:
> +  long l;
> +};
> +using CM = const M;
> +
> +SA( ! __is_invocable( M ) );
> +SA( ! __is_invocable( M& ) );
> +SA( ! __is_invocable( M&& ) );
> +SA( ! __is_invocable( M* ) );
> +SA( ! __is_invocable( CM ) );
> +SA( ! __is_invocable( CM& ) );
> +SA( ! __is_invocable( CM* ) );
> +
> +SA( ! __is_invocable( int M::* ) );
> +SA(   __is_invocable( int M::*, M ) );
> +SA(   __is_invocable( int M::*, M& ) );
> +SA(   __is_invocable( int M::*, M&& ) );
> +SA(   __is_invocable( int M::*, M* ) );
> +SA(   __is_invocable( int M::*, CM ) );
> +SA(   __is_invocable( int M::*, CM& ) );
> +SA(   __is_invocable( int M::*, CM* ) );
> +SA( ! __is_invocable( int M::*, int ) );
> +
> +SA( ! __is_invocable( int CM::* ) );
> +SA(   __is_invocable( int CM::*, M ) );
> +SA(   __is_invocable( int CM::*, M& ) );
> +SA(   __is_invocable( int CM::*, M&& ) );
> +SA(   __is_invocable( int CM::*, M* ) );
> +SA(   __is_invocable( int CM::*, CM ) );
> +SA(   __is_invocable( int CM::*, CM& ) );
> +SA(   __is_invocable( int CM::*, CM* ) );
> +SA( ! __is_invocable( int CM::*, int ) );
> +
> +SA( ! __is_invocable( long M::* ) );
> +SA(   __is_invocable( long M::*, M ) );
> +SA(   __is_invocable( long M::*, M& ) );
> +SA(   __is_invocable( long M::*, M&& ) );
> +SA(   __is_invocable( long M::*, M* ) );
> +SA(   __is_invocable( long M::*, CM ) );
> +SA(   __is_invocable( long M::*, CM& ) );
> +SA(   __is_invocable( long M::*, CM* ) );
> +SA( ! __is_invocable( long M::*, long ) );
> +
> +SA( ! __is_invocable( long CM::* ) );
> +SA(   __is_invocable( long CM::*, M ) );
> +SA(   __is_invocable( long CM::*, M& ) );
> +SA(   __is_invocable( long CM::*, M&& ) );
> +SA(   __is_invocable( long CM::*, M* ) );
> +SA(   __is_invocable( long CM::*, CM ) );
> +SA(   __is_invocable( long CM::*, CM& ) );
> +SA(   __is_invocable( long CM::*, CM* ) );
> +SA( ! __is_invocable( long CM::*, long ) );
> +
> +SA( ! __is_invocable( short M::* ) );
> +SA(   __is_invocable( short M::*, M ) );
> +SA(   __is_invocable( short M::*, M& ) );
> +SA(   __is_invocable( short M::*, M&& ) );
> +SA(   __is_invocable( short M::*, M* ) );
> +SA(   __is_invocable( short M::*, CM ) );
> +SA(   __is_invocable( short M::*, CM& ) );
> +SA(   __is_invocable( short M::*, CM* ) );
> +SA( ! __is_invocable( short M::*, short ) );
> +
> +SA( ! __is_invocable( short CM::* ) );
> +SA(   __is_invocable( short CM::*, M ) );
> +SA(   __is_invocable( short CM::*, M& ) );
> +SA(   __is_invocable( short CM::*, M&& ) );
> +SA(   __is_invocable( short CM::*, M* ) );
> +SA(   __is_invocable( short CM::*, CM ) );
> +SA(   __is_invocable( short CM::*, CM& ) );
> +SA(   __is_invocable( short CM::*, CM* ) );
> +SA( ! __is_invocable( short CM::*, short ) );
> +
> +struct N { M operator*(); };
> +SA(   __is_invocable( int M::*, N ) );
> +SA( ! __is_invocable( int M::*, N* ) );
> +
> +struct O { M& operator*(); };
> +SA(   __is_invocable( int M::*, O ) );
> +SA( ! __is_invocable( int M::*, O* ) );
> +
> +struct P { M&& operator*(); };
> +SA(   __is_invocable( int M::*, P ) );
> +SA( ! __is_invocable( int M::*, P* ) );
> +
> +struct Q { M* operator*(); };
> +SA( ! __is_invocable( int M::*, Q ) );
> +SA( ! __is_invocable( int M::*, Q* ) );
> +
> +struct R { void operator()(int = 0); };
> +
> +SA(   __is_invocable( R ) );
> +SA(   __is_invocable( R, int ) );
> +SA( ! __is_invocable( R, int, int ) );
> +
> +struct S { void operator()(int, ...); };
> +
> +SA( ! __is_invocable( S ) );
> +SA(   __is_invocable( S, int ) );
> +SA(   __is_invocable( S, int, int ) );
> +SA(   __is_invocable( S, int, int, int ) );
> +
> +void fn1() {}
> +
> +SA(   __is_invocable( decltype(fn1) ) );
> +
> +void fn2(int arr[10]);
> +
> +SA(   __is_invocable( decltype(fn2), int[10] ) );
> +SA(   __is_invocable( decltype(fn2), int(&)[10] ) );
> +SA(   __is_invocable( decltype(fn2), int(&&)[10] ) );
> +SA( ! __is_invocable( decltype(fn2), int(*)[10] ) );
> +SA( ! __is_invocable( decltype(fn2), int(*&)[10] ) );
> +SA( ! __is_invocable( decltype(fn2), int(*&&)[10] ) );
> +SA(   __is_invocable( decltype(fn2), int[] ) );
> +
> +auto lambda = []() {};
> +
> +SA(   __is_invocable( decltype(lambda) ) );
> +
> +template <typename Func, typename... Args>
> +struct can_invoke {
> +    static constexpr bool value = __is_invocable( Func, Args... );
> +};
> +
> +SA( can_invoke<decltype(lambda)>::value );
> +
> +struct T {
> +  void func() const {}
> +  int data;
> +};
> +
> +SA(   __is_invocable( decltype(&T::func)&, T& ) );
> +SA(   __is_invocable( decltype(&T::data)&, T& ) );
> diff --git a/gcc/testsuite/g++.dg/ext/is_invocable2.C b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> new file mode 100644
> index 00000000000..a68aefd3e13
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> @@ -0,0 +1,139 @@
> +// { dg-do compile { target c++11 } }
> +// __is_invocable should handle std::reference_wrapper correctly.
> +
> +#include <functional>
> +
> +#define SA(X) static_assert((X),#X)
> +
> +using std::reference_wrapper;
> +
> +using func_type_v0 = void(*)();
> +
> +SA(   __is_invocable( reference_wrapper<func_type_v0> ) );
> +SA( ! __is_invocable( reference_wrapper<func_type_v0>, int ) );
> +
> +using func_type_i0 = int(*)();
> +
> +SA(   __is_invocable( reference_wrapper<func_type_i0> ) );
> +SA( ! __is_invocable( reference_wrapper<func_type_i0>, int ) );
> +
> +using func_type_l0 = int&(*)();
> +
> +SA(   __is_invocable( reference_wrapper<func_type_l0> ) );
> +SA( ! __is_invocable( reference_wrapper<func_type_l0(int)> ) );
> +
> +using func_type_ii = int(*)(int);
> +
> +SA( ! __is_invocable( reference_wrapper<func_type_ii> ) );
> +SA(   __is_invocable( reference_wrapper<func_type_ii>, int ) );
> +
> +using func_type_il = int(*)(int&);
> +
> +SA( ! __is_invocable( reference_wrapper<func_type_il> ) );
> +SA( ! __is_invocable( reference_wrapper<func_type_il>, int ) );
> +SA(   __is_invocable( reference_wrapper<func_type_il>, int& ) );
> +
> +using func_type_ir = int(*)(int&&);
> +
> +SA( ! __is_invocable( reference_wrapper<func_type_ir> ) );
> +SA( ! __is_invocable( reference_wrapper<func_type_ir>, int& ) );
> +SA(   __is_invocable( reference_wrapper<func_type_ir>, int ) );
> +SA(   __is_invocable( reference_wrapper<func_type_ir>, int&& ) );
> +
> +struct A { };
> +
> +using mem_type_i = int A::*;
> +
> +SA( ! __is_invocable( reference_wrapper<mem_type_i> ) );
> +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int ) );
> +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int* ) );
> +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int& ) );
> +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int&& ) );
> +SA(   __is_invocable( reference_wrapper<mem_type_i>, A ) );
> +SA(   __is_invocable( reference_wrapper<mem_type_i>, A* ) );
> +SA(   __is_invocable( reference_wrapper<mem_type_i>, A& ) );
> +SA(   __is_invocable( reference_wrapper<mem_type_i>, A&& ) );
> +
> +using memfun_type_i = int (A::*)();
> +
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i> ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int* ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int&& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A* ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A&& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, const A& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, A&, int ) );
> +
> +using memfun_type_ic = int (A::*)() const;
> +
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic> ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A* ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A&, int ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A*, int& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A* ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A&, int& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A*, int ) );
> +
> +using memfun_type_iic = int& (A::*)(int&) const;
> +
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic> ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A&, int ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A&, int& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A*, int ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A*, int& ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int ) );
> +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int&, int ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int& ) );
> +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A*, int& ) );
> +
> +struct B {
> +  int& operator()();
> +  long& operator()() const;
> +  bool& operator()(int);
> +private:
> +  void operator()(int, int);
> +};
> +using CB = const B;
> +
> +SA(   __is_invocable( reference_wrapper<B> ) );
> +SA(   __is_invocable( reference_wrapper<B>& ) );
> +SA(   __is_invocable( reference_wrapper<B>&& ) );
> +SA(   __is_invocable( reference_wrapper<CB> ) );
> +SA(   __is_invocable( reference_wrapper<CB>& ) );
> +SA(   __is_invocable( reference_wrapper<B>, int ) );
> +SA( ! __is_invocable( reference_wrapper<B>&, int, int ) );
> +
> +struct C : B { int& operator()() = delete; };
> +using CC = const C;
> +
> +SA( ! __is_invocable( reference_wrapper<C> ) );
> +SA( ! __is_invocable( reference_wrapper<C>& ) );
> +SA( ! __is_invocable( reference_wrapper<C>&& ) );
> +SA( ! __is_invocable( reference_wrapper<CC> ) );
> +SA( ! __is_invocable( reference_wrapper<CC>& ) );
> +
> +struct D { B operator*(); };
> +using CD = const D;
> +
> +SA( ! __is_invocable( reference_wrapper<D> ) );
> +SA( ! __is_invocable( reference_wrapper<D>& ) );
> +SA( ! __is_invocable( reference_wrapper<D>&& ) );
> +SA( ! __is_invocable( reference_wrapper<D>* ) );
> +SA( ! __is_invocable( reference_wrapper<D*> ) );
> +SA( ! __is_invocable( reference_wrapper<D*>* ) );
> +
> +std::function<void()> fn = []() {};
> +auto refwrap = std::ref(fn);
> +
> +SA(   __is_invocable( decltype(fn) ) );
> +SA(   __is_invocable( decltype(refwrap) ) );
> diff --git a/gcc/testsuite/g++.dg/ext/is_invocable3.C b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> new file mode 100644
> index 00000000000..e2b0c5ef406
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> @@ -0,0 +1,51 @@
> +// { dg-do compile { target c++11 } }
> +// __is_invocable should handle incomplete class correctly.
> +
> +#define SA(X) static_assert((X),#X)
> +
> +struct Incomplete;
> +
> +SA( ! __is_invocable( Incomplete ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( Incomplete, int ) ); // { dg-error "incomplete type" }
> +
> +SA( ! __is_invocable( int, Incomplete, int ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( int, Incomplete ) ); // { dg-error "incomplete type" }
> +
> +SA( ! __is_invocable( Incomplete, Incomplete() ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( Incomplete, Incomplete(int), int ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( Incomplete, Incomplete(int, int), int, int ) ); // { dg-error "incomplete type" }
> +
> +SA( ! __is_invocable( Incomplete, Incomplete(), int, int ) ); // { dg-error "incomplete type" }
> +
> +SA( ! __is_invocable( int(Incomplete), Incomplete ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( int(int, Incomplete), int, Incomplete ) ); // { dg-error "incomplete type" }
> +SA( ! __is_invocable( int(int, Incomplete), Incomplete, int ) ); // { dg-error "incomplete type" }
> +
> +SA(   __is_invocable( int(Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( int(int, Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> +
> +SA(   __is_invocable( int(Incomplete&&), Incomplete&& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( int(int, Incomplete&&), int, Incomplete&& ) ); // { dg-bogus "incomplete type" }
> +
> +SA(   __is_invocable( int(const Incomplete&&), const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( int(int, const Incomplete&&), int, const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> +
> +SA(   __is_invocable( int(const Incomplete&), const Incomplete& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( int(int, const Incomplete&), int, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> +
> +SA(   __is_invocable( int(const Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( int(int, const Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> +
> +SA(   __is_invocable( int Incomplete::*, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> +SA( ! __is_invocable( void (Incomplete::*)(long&), const Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> +SA(   __is_invocable( void (Incomplete::*)(long&) const, Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> +
> +template <typename T>
> +struct Holder { T t; };
> +
> +SA(   __is_invocable( int(Holder<Incomplete>&), Holder<Incomplete>& ) ); // { dg-bogus "incomplete type" }
> +
> +// Define Incomplete, which is now not incomplete.
> +struct Incomplete { void operator()(); };
> +
> +SA( __is_invocable( Incomplete ) ); // { dg-bogus "incomplete type" }
> diff --git a/gcc/testsuite/g++.dg/ext/is_invocable4.C b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> new file mode 100644
> index 00000000000..d1efccf08f8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> @@ -0,0 +1,33 @@
> +// { dg-do compile { target c++11 } }
> +// Failed access check should be a substitution failure, not an error.
> +
> +#define SA(X) static_assert((X),#X)
> +
> +template<bool B>
> +struct bool_constant { static constexpr bool value = B; };
> +
> +template<typename _Fn, typename... _ArgTypes>
> +struct is_invocable
> +: public bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> +{ };
> +
> +#if __cpp_variable_templates
> +template<typename _Fn, typename... _ArgTypes>
> +constexpr bool is_invocable_v = __is_invocable(_Fn, _ArgTypes...);
> +#endif
> +
> +class Private
> +{
> +  void operator()() const
> +  {
> +    SA( ! is_invocable<Private>::value );
> +#if __cpp_variable_templates
> +    SA( ! is_invocable_v<Private> );
> +#endif
> +  }
> +};
> +
> +SA( ! is_invocable<Private>::value );
> +#if __cpp_variable_templates
> +SA( ! is_invocable_v<Private> );
> +#endif
> -- 
> 2.42.0
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-20 21:29                         ` Patrick Palka
@ 2023-10-20 21:31                           ` Patrick Palka
  2023-10-20 21:37                             ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-20 21:31 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Fri, 20 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Ken Matsui wrote:
> 
> > This patch implements built-in trait for std::is_invocable.
> 
> Nice!  My email client unfortunately ate my first review attempt, so
> apologies for my brevity this time around.
> 
> > gcc/cp/ChangeLog:
> > 
> > 	* cp-trait.def: Define __is_invocable.
> > 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
> > 	* semantics.cc (trait_expr_value): Likewise.
> > 	(finish_trait_expr): Likewise.
> > 	(is_invocable_p): New function.
> > 	* method.h: New file to export build_trait_object in method.cc.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
> > 	* g++.dg/ext/is_invocable1.C: New test.
> > 	* g++.dg/ext/is_invocable2.C: New test.
> > 	* g++.dg/ext/is_invocable3.C: New test.
> > 	* g++.dg/ext/is_invocable4.C: New test.
> > 
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  gcc/cp/constraint.cc                     |   6 +
> >  gcc/cp/cp-trait.def                      |   1 +
> >  gcc/cp/method.h                          |  28 ++
> >  gcc/cp/semantics.cc                      | 135 +++++++++
> >  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
> >  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++++++++++++++++++++++
> >  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 ++++++++++
> >  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 ++++
> >  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
> >  9 files changed, 733 insertions(+)
> >  create mode 100644 gcc/cp/method.h
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
> >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 9fce36e12d1..29bf548d30a 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3754,6 +3754,12 @@ diagnose_trait_expr (tree expr, tree args)
> >      case CPTK_IS_FUNCTION:
> >        inform (loc, "  %qT is not a function", t1);
> >        break;
> > +    case CPTK_IS_INVOCABLE:
> > +      if (!t2)
> > +    inform (loc, "  %qT is not invocable", t1);
> > +      else
> > +    inform (loc, "  %qT is not invocable by %qE", t1, t2);
> > +      break;
> >      case CPTK_IS_LAYOUT_COMPATIBLE:
> >        inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
> >        break;
> > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > index 05514a51c21..b8b7608c122 100644
> > --- a/gcc/cp/cp-trait.def
> > +++ b/gcc/cp/cp-trait.def
> > @@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
> >  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
> >  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
> >  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> > +DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
> >  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
> >  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
> >  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
> > diff --git a/gcc/cp/method.h b/gcc/cp/method.h
> > new file mode 100644
> > index 00000000000..1aec8ec5cfd
> > --- /dev/null
> > +++ b/gcc/cp/method.h
> > @@ -0,0 +1,28 @@
> > +/* Functions exported by method.cc.
> > +   Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify
> > +it under the terms of the GNU General Public License as published by
> > +the Free Software Foundation; either version 3, or (at your option)
> > +any later version.
> > +
> > +GCC is distributed in the hope that it will be useful,
> > +but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +GNU General Public License for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3.  If not see
> > +<http://www.gnu.org/licenses/>.  */
> > +
> > +#ifndef GCC_CP_METHOD_H
> > +#define GCC_CP_METHOD_H 1
> > +
> > +#include "tree.h"
> > +
> > +/* In method.cc  */
> > +extern tree build_trait_object (tree type);
> 
> Since other method.cc exports are already declared in cp-tree.h, for now
> let's just declare this in cp-tree.h as well (under build_stub_object)
> instead of creating a new header file.
> 
> > +
> > +#endif  /* GCC_CP_METHOD_H  */
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 7cccbae5287..cc2e400531a 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
> >  #include "gomp-constants.h"
> >  #include "predict.h"
> >  #include "memmodel.h"
> > +#include "method.h"
> > +
> > +#include "print-tree.h"
> > +#include "tree-pretty-print.h"
> >  
> >  /* There routines provide a modular interface to perform many parsing
> >     operations.  They may therefore be used during actual parsing, or
> > @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
> >    return saw_copy;
> >  }
> >  
> > +/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
> > +
> > +static bool
> > +is_invocable_p (tree fn_type, tree arg_types)
> > +{
> > +  /* ARG_TYPES must be a TREE_VEC.  */
> > +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
> > +
> > +  /* Access check is required to determine if the given is invocable.  */
> > +  deferring_access_check_sentinel acs (dk_no_deferred);
> > +
> > +  /* std::is_invocable is an unevaluated context.  */
> > +  cp_unevaluated cp_uneval_guard;
> > +
> > +  bool is_ptrdatamem;
> > +  bool is_ptrmemfunc;
> > +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
> > +    {
> > +      tree deref_fn_type = TREE_TYPE (fn_type);
> > +      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
> > +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
> > +
> > +      /* Dereference fn_type if it is a pointer to member.  */
> > +      if (is_ptrdatamem || is_ptrmemfunc)
> > +	fn_type = deref_fn_type;
> > +    }
> > +  else
> > +    {
> > +      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
> > +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
> > +    }
> > +
> > +  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
> > +    /* A pointer to data member with non-one argument is not invocable.  */
> > +    return false;
> > +
> > +  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
> > +    /* A pointer to member function with no arguments is not invocable.  */
> > +    return false;
> > +
> > +  /* Construct an expression of a pointer to member.  */
> > +  tree datum;
> > +  if (is_ptrdatamem || is_ptrmemfunc)
> > +    {
> > +      tree datum_type = TREE_VEC_ELT (arg_types, 0);
> > +
> > +      /* Dereference datum.  */
> > +      if (CLASS_TYPE_P (datum_type))
> > +	{
> > +	  bool is_refwrap = false;
> > +
> > +	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
> > +	  if (decl_in_std_namespace_p (datum_decl))
> > +	    {
> > +	      tree name = DECL_NAME (datum_decl);
> > +	      if (name && (id_equal (name, "reference_wrapper")))
> > +		{
> > +		  /* Handle std::reference_wrapper.  */
> > +		  is_refwrap = true;
> > +		  datum_type = cp_build_reference_type (datum_type, false);
> > +		}
> > +	    }
> > +
> > +	  datum = build_trait_object (datum_type);
> > +
> > +	  /* If datum_type was not std::reference_wrapper, check if it has
> > +	     operator*() overload.  If datum_type was std::reference_wrapper,
> > +	     avoid dereferencing the datum twice.  */
> > +	  if (!is_refwrap)
> > +	    if (get_class_binding (datum_type, get_identifier ("operator*")))
> 
> We probably should use lookup_member instead of get_class_binding since
> IIUC the latter doesn't look into bases:
> 
>   struct A { int m; };
>   struct B { A& operator*(): };
>   struct C : B { };
>   static_assert(std::is_invocable_v<int A::*, C>);
> 
> However, I notice that the specification of INVOKE
> (https://eel.is/c++draft/func.require#lib:INVOKE) doesn't mention name
> lookup at all so it strikes me as suspicious that we'd perform name
> lookup here.  I think this would misbehave for:
> 
>   struct A { };
>   struct B : A { A& operator*() = delete; };
>   static_assert(std::is_invocable_v<int A::*, B>);
> 
>   struct C : private A { A& operator*(); };
>   static_assert(std::is_invocable_v<int A::*, C>);

Oops, this static_assert is missing a !

> 
> ultimately because we end up choosing the dereference form of INVOKE,
> but according to 1.1/1.4 we should choose the non-dereference form?
> 
> > +	      /* Handle operator*().  */
> > +	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
> > +					    RO_UNARY_STAR, NULL_TREE,
> > +					    tf_none);
> > +	}
> > +      else if (POINTER_TYPE_P (datum_type))
> > +	datum = build_trait_object (TREE_TYPE (datum_type));
> > +      else
> > +	datum = build_trait_object (datum_type);
> > +    }
> > +
> > +  /* Build a function expression.  */
> > +  tree fn;
> > +  if (is_ptrdatamem)
> > +    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
> 
> Maybe exit early for the is_ptrdatamem case here (and simplify the rest
> of the function accordingly)?
> 
> > +  else if (is_ptrmemfunc)
> > +    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
> > +  else
> > +    fn = build_trait_object (fn_type);
> > +
> > +  /* Construct arguments to the function and an expression of a call.  */
> > +  if (!is_ptrdatamem)
> > +    {
> > +      releasing_vec args;
> > +
> > +      if (is_ptrmemfunc)
> > +	{
> > +	  /* A pointer to member function is internally converted to a pointer
> > +	     to function that takes a pointer to the dereferenced datum type
> > +	     as its first argument and original arguments afterward.  If the
> > +	     function is a const member function, the first argument also
> > +	     requires a const datum pointer and vice-versa.  */
> > +
> > +	  tree datum_type = TREE_TYPE (datum);
> > +	  if (TYPE_REF_P (datum_type))
> > +	    datum_type = TREE_TYPE (datum_type);
> > +
> > +	  datum = build_trait_object (build_pointer_type (datum_type));
> > +	  vec_safe_push (args, datum);
> > +	}
> > +
> > +      for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
> > +	{
> > +	  tree arg_type = TREE_VEC_ELT (arg_types, i);
> > +	  tree arg = build_trait_object (arg_type);
> > +	  vec_safe_push (args, arg);
> > +	}
> > +
> > +      fn = finish_call_expr (fn, &args, false, false, tf_none);
> > +    }
> > +
> > +  if (error_operand_p (fn))
> > +    return false;
> > +
> > +  return true;
> > +}
> > +
> >  /* Return true if DERIVED is pointer interconvertible base of BASE.  */
> >  
> >  static bool
> > @@ -12181,6 +12312,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> >      case CPTK_IS_FUNCTION:
> >        return type_code1 == FUNCTION_TYPE;
> >  
> > +    case CPTK_IS_INVOCABLE:
> > +      return is_invocable_p (type1, type2);
> > +
> >      case CPTK_IS_LAYOUT_COMPATIBLE:
> >        return layout_compatible_type_p (type1, type2);
> >  
> > @@ -12390,6 +12524,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> >        break;
> >  
> >      case CPTK_IS_CONVERTIBLE:
> > +    case CPTK_IS_INVOCABLE:
> >      case CPTK_IS_NOTHROW_ASSIGNABLE:
> >      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> >      case CPTK_IS_NOTHROW_CONVERTIBLE:
> > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > index b1430e9bd8b..3a9bda1ee03 100644
> > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > @@ -92,6 +92,9 @@
> >  #if !__has_builtin (__is_function)
> >  # error "__has_builtin (__is_function) failed"
> >  #endif
> > +#if !__has_builtin (__is_invocable)
> > +# error "__has_builtin (__is_invocable) failed"
> > +#endif
> >  #if !__has_builtin (__is_layout_compatible)
> >  # error "__has_builtin (__is_layout_compatible) failed"
> >  #endif
> > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable1.C b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> > new file mode 100644
> > index 00000000000..2fd3906b571
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> > @@ -0,0 +1,337 @@
> > +// { dg-do compile { target c++11 } }
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > +using func_type_v0 = void(*)();
> > +
> > +SA(   __is_invocable( func_type_v0 ) );
> > +SA( ! __is_invocable( func_type_v0, int ) );
> > +
> > +using func_type_i0 = int(*)();
> > +
> > +SA(   __is_invocable( func_type_i0 ) );
> > +SA( ! __is_invocable( func_type_i0, int ) );
> > +
> > +using func_type_l0 = int&(*)();
> > +
> > +SA(   __is_invocable( func_type_l0 ) );
> > +SA( ! __is_invocable( func_type_l0(int) ) );
> > +
> > +using func_type_ii = int(*)(int);
> > +
> > +SA( ! __is_invocable( func_type_ii ) );
> > +SA(   __is_invocable( func_type_ii, int ) );
> > +
> > +using func_type_il = int(*)(int&);
> > +
> > +SA( ! __is_invocable( func_type_il ) );
> > +SA( ! __is_invocable( func_type_il, int ) );
> > +SA(   __is_invocable( func_type_il, int& ) );
> > +
> > +using func_type_ir = int(*)(int&&);
> > +
> > +SA( ! __is_invocable( func_type_ir ) );
> > +SA( ! __is_invocable( func_type_ir, int& ) );
> > +SA(   __is_invocable( func_type_ir, int ) );
> > +SA(   __is_invocable( func_type_ir, int&& ) );
> > +
> > +struct A { };
> > +
> > +using mem_type_i = int A::*;
> > +
> > +SA( ! __is_invocable( mem_type_i ) );
> > +SA( ! __is_invocable( mem_type_i, int ) );
> > +SA( ! __is_invocable( mem_type_i, int* ) );
> > +SA( ! __is_invocable( mem_type_i, int& ) );
> > +SA( ! __is_invocable( mem_type_i, int&& ) );
> > +SA(   __is_invocable( mem_type_i, A ) );
> > +SA(   __is_invocable( mem_type_i, A* ) );
> > +SA(   __is_invocable( mem_type_i, A& ) );
> > +SA(   __is_invocable( mem_type_i, A&& ) );
> > +SA(   __is_invocable( mem_type_i, const A& ) );
> > +SA( ! __is_invocable( mem_type_i, A&, int ) );
> > +
> > +using memfun_type_i = int (A::*)();
> > +
> > +SA( ! __is_invocable( memfun_type_i ) );
> > +SA( ! __is_invocable( memfun_type_i, int ) );
> > +SA( ! __is_invocable( memfun_type_i, int* ) );
> > +SA( ! __is_invocable( memfun_type_i, int& ) );
> > +SA( ! __is_invocable( memfun_type_i, int&& ) );
> > +SA(   __is_invocable( memfun_type_i, A ) );
> > +SA(   __is_invocable( memfun_type_i, A* ) );
> > +SA(   __is_invocable( memfun_type_i, A& ) );
> > +SA(   __is_invocable( memfun_type_i, A&& ) );
> > +SA( ! __is_invocable( memfun_type_i, const A& ) );
> > +SA( ! __is_invocable( memfun_type_i, A&, int ) );
> > +
> > +using memfun_type_ic = int (A::*)() const;
> > +
> > +SA( ! __is_invocable( memfun_type_ic ) );
> > +SA( ! __is_invocable( memfun_type_ic, int ) );
> > +SA( ! __is_invocable( memfun_type_ic, int& ) );
> > +SA(   __is_invocable( memfun_type_ic, A& ) );
> > +SA(   __is_invocable( memfun_type_ic, A* ) );
> > +SA( ! __is_invocable( memfun_type_ic, A&, int ) );
> > +SA( ! __is_invocable( memfun_type_ic, A*, int& ) );
> > +SA(   __is_invocable( memfun_type_ic, const A& ) );
> > +SA(   __is_invocable( memfun_type_ic, const A* ) );
> > +SA( ! __is_invocable( memfun_type_ic, const A&, int& ) );
> > +SA( ! __is_invocable( memfun_type_ic, const A*, int ) );
> > +
> > +using memfun_type_iic = int& (A::*)(int&) const;
> > +
> > +SA( ! __is_invocable( memfun_type_iic ) );
> > +SA( ! __is_invocable( memfun_type_iic, int ) );
> > +SA( ! __is_invocable( memfun_type_iic, int& ) );
> > +SA( ! __is_invocable( memfun_type_iic, A&, int ) );
> > +SA(   __is_invocable( memfun_type_iic, A&, int& ) );
> > +SA( ! __is_invocable( memfun_type_iic, A*, int ) );
> > +SA(   __is_invocable( memfun_type_iic, A*, int& ) );
> > +SA( ! __is_invocable( memfun_type_iic, const A&, int ) );
> > +SA( ! __is_invocable( memfun_type_iic, const A&, int&, int ) );
> > +SA(   __is_invocable( memfun_type_iic, const A&, int& ) );
> > +SA(   __is_invocable( memfun_type_iic, const A*, int& ) );
> > +
> > +struct B {
> > +  int& operator()();
> > +  long& operator()() const;
> > +  bool& operator()(int);
> > +private:
> > +  void operator()(int, int);
> > +};
> > +using CB = const B;
> > +
> > +SA(   __is_invocable( B ) );
> > +SA(   __is_invocable( B& ) );
> > +SA(   __is_invocable( B&& ) );
> > +SA( ! __is_invocable( B* ) );
> > +SA(   __is_invocable( CB ) );
> > +SA(   __is_invocable( CB& ) );
> > +SA( ! __is_invocable( CB* ) );
> > +
> > +SA(   __is_invocable( B, int ) );
> > +SA(   __is_invocable( B&, int ) );
> > +SA(   __is_invocable( B&&, int ) );
> > +SA( ! __is_invocable( B*, int ) );
> > +SA( ! __is_invocable( CB, int ) );
> > +SA( ! __is_invocable( CB&, int ) );
> > +SA( ! __is_invocable( CB*, int ) );
> > +
> > +SA( ! __is_invocable( B, int, int ) );
> > +SA( ! __is_invocable( B&, int, int ) );
> > +SA( ! __is_invocable( B&&, int, int ) );
> > +SA( ! __is_invocable( B*, int, int ) );
> > +SA( ! __is_invocable( CB, int, int ) );
> > +SA( ! __is_invocable( CB&, int, int ) );
> > +SA( ! __is_invocable( CB*, int, int ) );
> > +
> > +struct C : B { int& operator()() = delete; };
> > +using CC = const C;
> > +
> > +SA( ! __is_invocable( C ) );
> > +SA( ! __is_invocable( C& ) );
> > +SA( ! __is_invocable( C&& ) );
> > +SA( ! __is_invocable( C* ) );
> > +SA( ! __is_invocable( CC ) );
> > +SA( ! __is_invocable( CC& ) );
> > +SA( ! __is_invocable( CC* ) );
> > +
> > +struct D { B operator*(); };
> > +using CD = const D;
> > +
> > +SA( ! __is_invocable( D ) );
> > +
> > +struct E { void v(); };
> > +using CE = const E;
> > +
> > +SA( ! __is_invocable( E ) );
> > +SA( ! __is_invocable( void (E::*)() ) );
> > +SA(   __is_invocable( void (E::*)(), E ) );
> > +SA(   __is_invocable( void (E::*)(), E* ) );
> > +SA( ! __is_invocable( void (E::*)(), CE ) );
> > +
> > +struct F : E {};
> > +using CF = const F;
> > +
> > +SA( ! __is_invocable( F ) );
> > +SA(   __is_invocable( void (E::*)(), F ) );
> > +SA(   __is_invocable( void (E::*)(), F* ) );
> > +SA( ! __is_invocable( void (E::*)(), CF ) );
> > +
> > +struct G { E operator*(); };
> > +using CG = const G;
> > +
> > +SA( ! __is_invocable( G ) );
> > +SA(   __is_invocable( void (E::*)(), G ) );
> > +SA( ! __is_invocable( void (E::*)(), G* ) );
> > +SA( ! __is_invocable( void (E::*)(), CG ) );
> > +
> > +struct H { E& operator*(); };
> > +using CH = const H;
> > +
> > +SA( ! __is_invocable( H ) );
> > +SA(   __is_invocable( void (E::*)(), H ) );
> > +SA( ! __is_invocable( void (E::*)(), H* ) );
> > +SA( ! __is_invocable( void (E::*)(), CH ) );
> > +
> > +struct I { E&& operator*(); };
> > +using CI = const I;
> > +
> > +SA( ! __is_invocable( I ) );
> > +SA(   __is_invocable( void (E::*)(), I ) );
> > +SA( ! __is_invocable( void (E::*)(), I* ) );
> > +SA( ! __is_invocable( void (E::*)(), CI ) );
> > +
> > +struct K { E* operator*(); };
> > +using CK = const K;
> > +
> > +SA( ! __is_invocable( K ) );
> > +SA( ! __is_invocable( void (E::*)(), K ) );
> > +SA( ! __is_invocable( void (E::*)(), K* ) );
> > +SA( ! __is_invocable( void (E::*)(), CK ) );
> > +
> > +struct L { CE operator*(); };
> > +using CL = const L;
> > +
> > +SA( ! __is_invocable( L ) );
> > +SA( ! __is_invocable( void (E::*)(), L ) );
> > +SA( ! __is_invocable( void (E::*)(), L* ) );
> > +SA( ! __is_invocable( void (E::*)(), CL ) );
> > +
> > +struct M {
> > +  int i;
> > +private:
> > +  long l;
> > +};
> > +using CM = const M;
> > +
> > +SA( ! __is_invocable( M ) );
> > +SA( ! __is_invocable( M& ) );
> > +SA( ! __is_invocable( M&& ) );
> > +SA( ! __is_invocable( M* ) );
> > +SA( ! __is_invocable( CM ) );
> > +SA( ! __is_invocable( CM& ) );
> > +SA( ! __is_invocable( CM* ) );
> > +
> > +SA( ! __is_invocable( int M::* ) );
> > +SA(   __is_invocable( int M::*, M ) );
> > +SA(   __is_invocable( int M::*, M& ) );
> > +SA(   __is_invocable( int M::*, M&& ) );
> > +SA(   __is_invocable( int M::*, M* ) );
> > +SA(   __is_invocable( int M::*, CM ) );
> > +SA(   __is_invocable( int M::*, CM& ) );
> > +SA(   __is_invocable( int M::*, CM* ) );
> > +SA( ! __is_invocable( int M::*, int ) );
> > +
> > +SA( ! __is_invocable( int CM::* ) );
> > +SA(   __is_invocable( int CM::*, M ) );
> > +SA(   __is_invocable( int CM::*, M& ) );
> > +SA(   __is_invocable( int CM::*, M&& ) );
> > +SA(   __is_invocable( int CM::*, M* ) );
> > +SA(   __is_invocable( int CM::*, CM ) );
> > +SA(   __is_invocable( int CM::*, CM& ) );
> > +SA(   __is_invocable( int CM::*, CM* ) );
> > +SA( ! __is_invocable( int CM::*, int ) );
> > +
> > +SA( ! __is_invocable( long M::* ) );
> > +SA(   __is_invocable( long M::*, M ) );
> > +SA(   __is_invocable( long M::*, M& ) );
> > +SA(   __is_invocable( long M::*, M&& ) );
> > +SA(   __is_invocable( long M::*, M* ) );
> > +SA(   __is_invocable( long M::*, CM ) );
> > +SA(   __is_invocable( long M::*, CM& ) );
> > +SA(   __is_invocable( long M::*, CM* ) );
> > +SA( ! __is_invocable( long M::*, long ) );
> > +
> > +SA( ! __is_invocable( long CM::* ) );
> > +SA(   __is_invocable( long CM::*, M ) );
> > +SA(   __is_invocable( long CM::*, M& ) );
> > +SA(   __is_invocable( long CM::*, M&& ) );
> > +SA(   __is_invocable( long CM::*, M* ) );
> > +SA(   __is_invocable( long CM::*, CM ) );
> > +SA(   __is_invocable( long CM::*, CM& ) );
> > +SA(   __is_invocable( long CM::*, CM* ) );
> > +SA( ! __is_invocable( long CM::*, long ) );
> > +
> > +SA( ! __is_invocable( short M::* ) );
> > +SA(   __is_invocable( short M::*, M ) );
> > +SA(   __is_invocable( short M::*, M& ) );
> > +SA(   __is_invocable( short M::*, M&& ) );
> > +SA(   __is_invocable( short M::*, M* ) );
> > +SA(   __is_invocable( short M::*, CM ) );
> > +SA(   __is_invocable( short M::*, CM& ) );
> > +SA(   __is_invocable( short M::*, CM* ) );
> > +SA( ! __is_invocable( short M::*, short ) );
> > +
> > +SA( ! __is_invocable( short CM::* ) );
> > +SA(   __is_invocable( short CM::*, M ) );
> > +SA(   __is_invocable( short CM::*, M& ) );
> > +SA(   __is_invocable( short CM::*, M&& ) );
> > +SA(   __is_invocable( short CM::*, M* ) );
> > +SA(   __is_invocable( short CM::*, CM ) );
> > +SA(   __is_invocable( short CM::*, CM& ) );
> > +SA(   __is_invocable( short CM::*, CM* ) );
> > +SA( ! __is_invocable( short CM::*, short ) );
> > +
> > +struct N { M operator*(); };
> > +SA(   __is_invocable( int M::*, N ) );
> > +SA( ! __is_invocable( int M::*, N* ) );
> > +
> > +struct O { M& operator*(); };
> > +SA(   __is_invocable( int M::*, O ) );
> > +SA( ! __is_invocable( int M::*, O* ) );
> > +
> > +struct P { M&& operator*(); };
> > +SA(   __is_invocable( int M::*, P ) );
> > +SA( ! __is_invocable( int M::*, P* ) );
> > +
> > +struct Q { M* operator*(); };
> > +SA( ! __is_invocable( int M::*, Q ) );
> > +SA( ! __is_invocable( int M::*, Q* ) );
> > +
> > +struct R { void operator()(int = 0); };
> > +
> > +SA(   __is_invocable( R ) );
> > +SA(   __is_invocable( R, int ) );
> > +SA( ! __is_invocable( R, int, int ) );
> > +
> > +struct S { void operator()(int, ...); };
> > +
> > +SA( ! __is_invocable( S ) );
> > +SA(   __is_invocable( S, int ) );
> > +SA(   __is_invocable( S, int, int ) );
> > +SA(   __is_invocable( S, int, int, int ) );
> > +
> > +void fn1() {}
> > +
> > +SA(   __is_invocable( decltype(fn1) ) );
> > +
> > +void fn2(int arr[10]);
> > +
> > +SA(   __is_invocable( decltype(fn2), int[10] ) );
> > +SA(   __is_invocable( decltype(fn2), int(&)[10] ) );
> > +SA(   __is_invocable( decltype(fn2), int(&&)[10] ) );
> > +SA( ! __is_invocable( decltype(fn2), int(*)[10] ) );
> > +SA( ! __is_invocable( decltype(fn2), int(*&)[10] ) );
> > +SA( ! __is_invocable( decltype(fn2), int(*&&)[10] ) );
> > +SA(   __is_invocable( decltype(fn2), int[] ) );
> > +
> > +auto lambda = []() {};
> > +
> > +SA(   __is_invocable( decltype(lambda) ) );
> > +
> > +template <typename Func, typename... Args>
> > +struct can_invoke {
> > +    static constexpr bool value = __is_invocable( Func, Args... );
> > +};
> > +
> > +SA( can_invoke<decltype(lambda)>::value );
> > +
> > +struct T {
> > +  void func() const {}
> > +  int data;
> > +};
> > +
> > +SA(   __is_invocable( decltype(&T::func)&, T& ) );
> > +SA(   __is_invocable( decltype(&T::data)&, T& ) );
> > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable2.C b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> > new file mode 100644
> > index 00000000000..a68aefd3e13
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> > @@ -0,0 +1,139 @@
> > +// { dg-do compile { target c++11 } }
> > +// __is_invocable should handle std::reference_wrapper correctly.
> > +
> > +#include <functional>
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > +using std::reference_wrapper;
> > +
> > +using func_type_v0 = void(*)();
> > +
> > +SA(   __is_invocable( reference_wrapper<func_type_v0> ) );
> > +SA( ! __is_invocable( reference_wrapper<func_type_v0>, int ) );
> > +
> > +using func_type_i0 = int(*)();
> > +
> > +SA(   __is_invocable( reference_wrapper<func_type_i0> ) );
> > +SA( ! __is_invocable( reference_wrapper<func_type_i0>, int ) );
> > +
> > +using func_type_l0 = int&(*)();
> > +
> > +SA(   __is_invocable( reference_wrapper<func_type_l0> ) );
> > +SA( ! __is_invocable( reference_wrapper<func_type_l0(int)> ) );
> > +
> > +using func_type_ii = int(*)(int);
> > +
> > +SA( ! __is_invocable( reference_wrapper<func_type_ii> ) );
> > +SA(   __is_invocable( reference_wrapper<func_type_ii>, int ) );
> > +
> > +using func_type_il = int(*)(int&);
> > +
> > +SA( ! __is_invocable( reference_wrapper<func_type_il> ) );
> > +SA( ! __is_invocable( reference_wrapper<func_type_il>, int ) );
> > +SA(   __is_invocable( reference_wrapper<func_type_il>, int& ) );
> > +
> > +using func_type_ir = int(*)(int&&);
> > +
> > +SA( ! __is_invocable( reference_wrapper<func_type_ir> ) );
> > +SA( ! __is_invocable( reference_wrapper<func_type_ir>, int& ) );
> > +SA(   __is_invocable( reference_wrapper<func_type_ir>, int ) );
> > +SA(   __is_invocable( reference_wrapper<func_type_ir>, int&& ) );
> > +
> > +struct A { };
> > +
> > +using mem_type_i = int A::*;
> > +
> > +SA( ! __is_invocable( reference_wrapper<mem_type_i> ) );
> > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int ) );
> > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int* ) );
> > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int&& ) );
> > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A ) );
> > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A* ) );
> > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A& ) );
> > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A&& ) );
> > +
> > +using memfun_type_i = int (A::*)();
> > +
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i> ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int* ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int&& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A* ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A&& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, const A& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, A&, int ) );
> > +
> > +using memfun_type_ic = int (A::*)() const;
> > +
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic> ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A* ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A&, int ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A*, int& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A* ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A&, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A*, int ) );
> > +
> > +using memfun_type_iic = int& (A::*)(int&) const;
> > +
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic> ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A&, int ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A&, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A*, int ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A*, int& ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int ) );
> > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int&, int ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int& ) );
> > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A*, int& ) );
> > +
> > +struct B {
> > +  int& operator()();
> > +  long& operator()() const;
> > +  bool& operator()(int);
> > +private:
> > +  void operator()(int, int);
> > +};
> > +using CB = const B;
> > +
> > +SA(   __is_invocable( reference_wrapper<B> ) );
> > +SA(   __is_invocable( reference_wrapper<B>& ) );
> > +SA(   __is_invocable( reference_wrapper<B>&& ) );
> > +SA(   __is_invocable( reference_wrapper<CB> ) );
> > +SA(   __is_invocable( reference_wrapper<CB>& ) );
> > +SA(   __is_invocable( reference_wrapper<B>, int ) );
> > +SA( ! __is_invocable( reference_wrapper<B>&, int, int ) );
> > +
> > +struct C : B { int& operator()() = delete; };
> > +using CC = const C;
> > +
> > +SA( ! __is_invocable( reference_wrapper<C> ) );
> > +SA( ! __is_invocable( reference_wrapper<C>& ) );
> > +SA( ! __is_invocable( reference_wrapper<C>&& ) );
> > +SA( ! __is_invocable( reference_wrapper<CC> ) );
> > +SA( ! __is_invocable( reference_wrapper<CC>& ) );
> > +
> > +struct D { B operator*(); };
> > +using CD = const D;
> > +
> > +SA( ! __is_invocable( reference_wrapper<D> ) );
> > +SA( ! __is_invocable( reference_wrapper<D>& ) );
> > +SA( ! __is_invocable( reference_wrapper<D>&& ) );
> > +SA( ! __is_invocable( reference_wrapper<D>* ) );
> > +SA( ! __is_invocable( reference_wrapper<D*> ) );
> > +SA( ! __is_invocable( reference_wrapper<D*>* ) );
> > +
> > +std::function<void()> fn = []() {};
> > +auto refwrap = std::ref(fn);
> > +
> > +SA(   __is_invocable( decltype(fn) ) );
> > +SA(   __is_invocable( decltype(refwrap) ) );
> > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable3.C b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> > new file mode 100644
> > index 00000000000..e2b0c5ef406
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> > @@ -0,0 +1,51 @@
> > +// { dg-do compile { target c++11 } }
> > +// __is_invocable should handle incomplete class correctly.
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > +struct Incomplete;
> > +
> > +SA( ! __is_invocable( Incomplete ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( Incomplete, int ) ); // { dg-error "incomplete type" }
> > +
> > +SA( ! __is_invocable( int, Incomplete, int ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( int, Incomplete ) ); // { dg-error "incomplete type" }
> > +
> > +SA( ! __is_invocable( Incomplete, Incomplete() ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( Incomplete, Incomplete(int), int ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( Incomplete, Incomplete(int, int), int, int ) ); // { dg-error "incomplete type" }
> > +
> > +SA( ! __is_invocable( Incomplete, Incomplete(), int, int ) ); // { dg-error "incomplete type" }
> > +
> > +SA( ! __is_invocable( int(Incomplete), Incomplete ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( int(int, Incomplete), int, Incomplete ) ); // { dg-error "incomplete type" }
> > +SA( ! __is_invocable( int(int, Incomplete), Incomplete, int ) ); // { dg-error "incomplete type" }
> > +
> > +SA(   __is_invocable( int(Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( int(int, Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +
> > +SA(   __is_invocable( int(Incomplete&&), Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( int(int, Incomplete&&), int, Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > +
> > +SA(   __is_invocable( int(const Incomplete&&), const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( int(int, const Incomplete&&), int, const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > +
> > +SA(   __is_invocable( int(const Incomplete&), const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( int(int, const Incomplete&), int, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +
> > +SA(   __is_invocable( int(const Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( int(int, const Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +
> > +SA(   __is_invocable( int Incomplete::*, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > +SA( ! __is_invocable( void (Incomplete::*)(long&), const Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> > +SA(   __is_invocable( void (Incomplete::*)(long&) const, Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> > +
> > +template <typename T>
> > +struct Holder { T t; };
> > +
> > +SA(   __is_invocable( int(Holder<Incomplete>&), Holder<Incomplete>& ) ); // { dg-bogus "incomplete type" }
> > +
> > +// Define Incomplete, which is now not incomplete.
> > +struct Incomplete { void operator()(); };
> > +
> > +SA( __is_invocable( Incomplete ) ); // { dg-bogus "incomplete type" }
> > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable4.C b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> > new file mode 100644
> > index 00000000000..d1efccf08f8
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> > @@ -0,0 +1,33 @@
> > +// { dg-do compile { target c++11 } }
> > +// Failed access check should be a substitution failure, not an error.
> > +
> > +#define SA(X) static_assert((X),#X)
> > +
> > +template<bool B>
> > +struct bool_constant { static constexpr bool value = B; };
> > +
> > +template<typename _Fn, typename... _ArgTypes>
> > +struct is_invocable
> > +: public bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> > +{ };
> > +
> > +#if __cpp_variable_templates
> > +template<typename _Fn, typename... _ArgTypes>
> > +constexpr bool is_invocable_v = __is_invocable(_Fn, _ArgTypes...);
> > +#endif
> > +
> > +class Private
> > +{
> > +  void operator()() const
> > +  {
> > +    SA( ! is_invocable<Private>::value );
> > +#if __cpp_variable_templates
> > +    SA( ! is_invocable_v<Private> );
> > +#endif
> > +  }
> > +};
> > +
> > +SA( ! is_invocable<Private>::value );
> > +#if __cpp_variable_templates
> > +SA( ! is_invocable_v<Private> );
> > +#endif
> > -- 
> > 2.42.0
> > 
> > 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-20 21:31                           ` Patrick Palka
@ 2023-10-20 21:37                             ` Patrick Palka
  2023-10-23 21:23                               ` Jason Merrill
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-20 21:37 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Fri, 20 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Patrick Palka wrote:
> 
> > On Fri, 20 Oct 2023, Ken Matsui wrote:
> > 
> > > This patch implements built-in trait for std::is_invocable.
> > 
> > Nice!  My email client unfortunately ate my first review attempt, so
> > apologies for my brevity this time around.
> > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	* cp-trait.def: Define __is_invocable.
> > > 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
> > > 	* semantics.cc (trait_expr_value): Likewise.
> > > 	(finish_trait_expr): Likewise.
> > > 	(is_invocable_p): New function.
> > > 	* method.h: New file to export build_trait_object in method.cc.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
> > > 	* g++.dg/ext/is_invocable1.C: New test.
> > > 	* g++.dg/ext/is_invocable2.C: New test.
> > > 	* g++.dg/ext/is_invocable3.C: New test.
> > > 	* g++.dg/ext/is_invocable4.C: New test.
> > > 
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > >  gcc/cp/constraint.cc                     |   6 +
> > >  gcc/cp/cp-trait.def                      |   1 +
> > >  gcc/cp/method.h                          |  28 ++
> > >  gcc/cp/semantics.cc                      | 135 +++++++++
> > >  gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
> > >  gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++++++++++++++++++++++
> > >  gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 ++++++++++
> > >  gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 ++++
> > >  gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
> > >  9 files changed, 733 insertions(+)
> > >  create mode 100644 gcc/cp/method.h
> > >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
> > >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
> > >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
> > >  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
> > > 
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index 9fce36e12d1..29bf548d30a 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3754,6 +3754,12 @@ diagnose_trait_expr (tree expr, tree args)
> > >      case CPTK_IS_FUNCTION:
> > >        inform (loc, "  %qT is not a function", t1);
> > >        break;
> > > +    case CPTK_IS_INVOCABLE:
> > > +      if (!t2)
> > > +    inform (loc, "  %qT is not invocable", t1);
> > > +      else
> > > +    inform (loc, "  %qT is not invocable by %qE", t1, t2);
> > > +      break;
> > >      case CPTK_IS_LAYOUT_COMPATIBLE:
> > >        inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
> > >        break;
> > > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
> > > index 05514a51c21..b8b7608c122 100644
> > > --- a/gcc/cp/cp-trait.def
> > > +++ b/gcc/cp/cp-trait.def
> > > @@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
> > >  DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
> > >  DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
> > >  DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
> > > +DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
> > >  DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
> > >  DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
> > >  DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
> > > diff --git a/gcc/cp/method.h b/gcc/cp/method.h
> > > new file mode 100644
> > > index 00000000000..1aec8ec5cfd
> > > --- /dev/null
> > > +++ b/gcc/cp/method.h
> > > @@ -0,0 +1,28 @@
> > > +/* Functions exported by method.cc.
> > > +   Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify
> > > +it under the terms of the GNU General Public License as published by
> > > +the Free Software Foundation; either version 3, or (at your option)
> > > +any later version.
> > > +
> > > +GCC is distributed in the hope that it will be useful,
> > > +but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > +GNU General Public License for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3.  If not see
> > > +<http://www.gnu.org/licenses/>.  */
> > > +
> > > +#ifndef GCC_CP_METHOD_H
> > > +#define GCC_CP_METHOD_H 1
> > > +
> > > +#include "tree.h"
> > > +
> > > +/* In method.cc  */
> > > +extern tree build_trait_object (tree type);
> > 
> > Since other method.cc exports are already declared in cp-tree.h, for now
> > let's just declare this in cp-tree.h as well (under build_stub_object)
> > instead of creating a new header file.
> > 
> > > +
> > > +#endif  /* GCC_CP_METHOD_H  */
> > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > > index 7cccbae5287..cc2e400531a 100644
> > > --- a/gcc/cp/semantics.cc
> > > +++ b/gcc/cp/semantics.cc
> > > @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
> > >  #include "gomp-constants.h"
> > >  #include "predict.h"
> > >  #include "memmodel.h"
> > > +#include "method.h"
> > > +
> > > +#include "print-tree.h"
> > > +#include "tree-pretty-print.h"
> > >  
> > >  /* There routines provide a modular interface to perform many parsing
> > >     operations.  They may therefore be used during actual parsing, or
> > > @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
> > >    return saw_copy;
> > >  }
> > >  
> > > +/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
> > > +
> > > +static bool
> > > +is_invocable_p (tree fn_type, tree arg_types)

(Sorry for the spam)  We'll eventually want to implement a built-in for
invoke_result, so perhaps we should preemptively factor out the bulk
of this function into a 'build_INVOKE' helper function that returns the
built tree?

> > > +{
> > > +  /* ARG_TYPES must be a TREE_VEC.  */
> > > +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
> > > +
> > > +  /* Access check is required to determine if the given is invocable.  */
> > > +  deferring_access_check_sentinel acs (dk_no_deferred);
> > > +
> > > +  /* std::is_invocable is an unevaluated context.  */
> > > +  cp_unevaluated cp_uneval_guard;
> > > +
> > > +  bool is_ptrdatamem;
> > > +  bool is_ptrmemfunc;
> > > +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
> > > +    {
> > > +      tree deref_fn_type = TREE_TYPE (fn_type);
> > > +      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
> > > +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
> > > +
> > > +      /* Dereference fn_type if it is a pointer to member.  */
> > > +      if (is_ptrdatamem || is_ptrmemfunc)
> > > +	fn_type = deref_fn_type;
> > > +    }
> > > +  else
> > > +    {
> > > +      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
> > > +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
> > > +    }
> > > +
> > > +  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
> > > +    /* A pointer to data member with non-one argument is not invocable.  */
> > > +    return false;
> > > +
> > > +  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
> > > +    /* A pointer to member function with no arguments is not invocable.  */
> > > +    return false;
> > > +
> > > +  /* Construct an expression of a pointer to member.  */
> > > +  tree datum;
> > > +  if (is_ptrdatamem || is_ptrmemfunc)
> > > +    {
> > > +      tree datum_type = TREE_VEC_ELT (arg_types, 0);
> > > +
> > > +      /* Dereference datum.  */
> > > +      if (CLASS_TYPE_P (datum_type))
> > > +	{
> > > +	  bool is_refwrap = false;
> > > +
> > > +	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
> > > +	  if (decl_in_std_namespace_p (datum_decl))
> > > +	    {
> > > +	      tree name = DECL_NAME (datum_decl);
> > > +	      if (name && (id_equal (name, "reference_wrapper")))
> > > +		{
> > > +		  /* Handle std::reference_wrapper.  */
> > > +		  is_refwrap = true;
> > > +		  datum_type = cp_build_reference_type (datum_type, false);
> > > +		}
> > > +	    }
> > > +
> > > +	  datum = build_trait_object (datum_type);
> > > +
> > > +	  /* If datum_type was not std::reference_wrapper, check if it has
> > > +	     operator*() overload.  If datum_type was std::reference_wrapper,
> > > +	     avoid dereferencing the datum twice.  */
> > > +	  if (!is_refwrap)
> > > +	    if (get_class_binding (datum_type, get_identifier ("operator*")))
> > 
> > We probably should use lookup_member instead of get_class_binding since
> > IIUC the latter doesn't look into bases:
> > 
> >   struct A { int m; };
> >   struct B { A& operator*(): };
> >   struct C : B { };
> >   static_assert(std::is_invocable_v<int A::*, C>);
> > 
> > However, I notice that the specification of INVOKE
> > (https://eel.is/c++draft/func.require#lib:INVOKE) doesn't mention name
> > lookup at all so it strikes me as suspicious that we'd perform name
> > lookup here.  I think this would misbehave for:
> > 
> >   struct A { };
> >   struct B : A { A& operator*() = delete; };
> >   static_assert(std::is_invocable_v<int A::*, B>);
> > 
> >   struct C : private A { A& operator*(); };
> >   static_assert(std::is_invocable_v<int A::*, C>);
> 
> Oops, this static_assert is missing a !
> 
> > 
> > ultimately because we end up choosing the dereference form of INVOKE,
> > but according to 1.1/1.4 we should choose the non-dereference form?
> > 
> > > +	      /* Handle operator*().  */
> > > +	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
> > > +					    RO_UNARY_STAR, NULL_TREE,
> > > +					    tf_none);
> > > +	}
> > > +      else if (POINTER_TYPE_P (datum_type))
> > > +	datum = build_trait_object (TREE_TYPE (datum_type));
> > > +      else
> > > +	datum = build_trait_object (datum_type);
> > > +    }
> > > +
> > > +  /* Build a function expression.  */
> > > +  tree fn;
> > > +  if (is_ptrdatamem)
> > > +    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
> > 
> > Maybe exit early for the is_ptrdatamem case here (and simplify the rest
> > of the function accordingly)?
> > 
> > > +  else if (is_ptrmemfunc)
> > > +    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
> > > +  else
> > > +    fn = build_trait_object (fn_type);
> > > +
> > > +  /* Construct arguments to the function and an expression of a call.  */
> > > +  if (!is_ptrdatamem)
> > > +    {
> > > +      releasing_vec args;
> > > +
> > > +      if (is_ptrmemfunc)
> > > +	{
> > > +	  /* A pointer to member function is internally converted to a pointer
> > > +	     to function that takes a pointer to the dereferenced datum type
> > > +	     as its first argument and original arguments afterward.  If the
> > > +	     function is a const member function, the first argument also
> > > +	     requires a const datum pointer and vice-versa.  */
> > > +
> > > +	  tree datum_type = TREE_TYPE (datum);
> > > +	  if (TYPE_REF_P (datum_type))
> > > +	    datum_type = TREE_TYPE (datum_type);
> > > +
> > > +	  datum = build_trait_object (build_pointer_type (datum_type));
> > > +	  vec_safe_push (args, datum);
> > > +	}
> > > +
> > > +      for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
> > > +	{
> > > +	  tree arg_type = TREE_VEC_ELT (arg_types, i);
> > > +	  tree arg = build_trait_object (arg_type);
> > > +	  vec_safe_push (args, arg);
> > > +	}
> > > +
> > > +      fn = finish_call_expr (fn, &args, false, false, tf_none);
> > > +    }
> > > +
> > > +  if (error_operand_p (fn))
> > > +    return false;
> > > +
> > > +  return true;
> > > +}
> > > +
> > >  /* Return true if DERIVED is pointer interconvertible base of BASE.  */
> > >  
> > >  static bool
> > > @@ -12181,6 +12312,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
> > >      case CPTK_IS_FUNCTION:
> > >        return type_code1 == FUNCTION_TYPE;
> > >  
> > > +    case CPTK_IS_INVOCABLE:
> > > +      return is_invocable_p (type1, type2);
> > > +
> > >      case CPTK_IS_LAYOUT_COMPATIBLE:
> > >        return layout_compatible_type_p (type1, type2);
> > >  
> > > @@ -12390,6 +12524,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> > >        break;
> > >  
> > >      case CPTK_IS_CONVERTIBLE:
> > > +    case CPTK_IS_INVOCABLE:
> > >      case CPTK_IS_NOTHROW_ASSIGNABLE:
> > >      case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
> > >      case CPTK_IS_NOTHROW_CONVERTIBLE:
> > > diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > index b1430e9bd8b..3a9bda1ee03 100644
> > > --- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > +++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
> > > @@ -92,6 +92,9 @@
> > >  #if !__has_builtin (__is_function)
> > >  # error "__has_builtin (__is_function) failed"
> > >  #endif
> > > +#if !__has_builtin (__is_invocable)
> > > +# error "__has_builtin (__is_invocable) failed"
> > > +#endif
> > >  #if !__has_builtin (__is_layout_compatible)
> > >  # error "__has_builtin (__is_layout_compatible) failed"
> > >  #endif
> > > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable1.C b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> > > new file mode 100644
> > > index 00000000000..2fd3906b571
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/ext/is_invocable1.C
> > > @@ -0,0 +1,337 @@
> > > +// { dg-do compile { target c++11 } }
> > > +
> > > +#define SA(X) static_assert((X),#X)
> > > +
> > > +using func_type_v0 = void(*)();
> > > +
> > > +SA(   __is_invocable( func_type_v0 ) );
> > > +SA( ! __is_invocable( func_type_v0, int ) );
> > > +
> > > +using func_type_i0 = int(*)();
> > > +
> > > +SA(   __is_invocable( func_type_i0 ) );
> > > +SA( ! __is_invocable( func_type_i0, int ) );
> > > +
> > > +using func_type_l0 = int&(*)();
> > > +
> > > +SA(   __is_invocable( func_type_l0 ) );
> > > +SA( ! __is_invocable( func_type_l0(int) ) );
> > > +
> > > +using func_type_ii = int(*)(int);
> > > +
> > > +SA( ! __is_invocable( func_type_ii ) );
> > > +SA(   __is_invocable( func_type_ii, int ) );
> > > +
> > > +using func_type_il = int(*)(int&);
> > > +
> > > +SA( ! __is_invocable( func_type_il ) );
> > > +SA( ! __is_invocable( func_type_il, int ) );
> > > +SA(   __is_invocable( func_type_il, int& ) );
> > > +
> > > +using func_type_ir = int(*)(int&&);
> > > +
> > > +SA( ! __is_invocable( func_type_ir ) );
> > > +SA( ! __is_invocable( func_type_ir, int& ) );
> > > +SA(   __is_invocable( func_type_ir, int ) );
> > > +SA(   __is_invocable( func_type_ir, int&& ) );
> > > +
> > > +struct A { };
> > > +
> > > +using mem_type_i = int A::*;
> > > +
> > > +SA( ! __is_invocable( mem_type_i ) );
> > > +SA( ! __is_invocable( mem_type_i, int ) );
> > > +SA( ! __is_invocable( mem_type_i, int* ) );
> > > +SA( ! __is_invocable( mem_type_i, int& ) );
> > > +SA( ! __is_invocable( mem_type_i, int&& ) );
> > > +SA(   __is_invocable( mem_type_i, A ) );
> > > +SA(   __is_invocable( mem_type_i, A* ) );
> > > +SA(   __is_invocable( mem_type_i, A& ) );
> > > +SA(   __is_invocable( mem_type_i, A&& ) );
> > > +SA(   __is_invocable( mem_type_i, const A& ) );
> > > +SA( ! __is_invocable( mem_type_i, A&, int ) );
> > > +
> > > +using memfun_type_i = int (A::*)();
> > > +
> > > +SA( ! __is_invocable( memfun_type_i ) );
> > > +SA( ! __is_invocable( memfun_type_i, int ) );
> > > +SA( ! __is_invocable( memfun_type_i, int* ) );
> > > +SA( ! __is_invocable( memfun_type_i, int& ) );
> > > +SA( ! __is_invocable( memfun_type_i, int&& ) );
> > > +SA(   __is_invocable( memfun_type_i, A ) );
> > > +SA(   __is_invocable( memfun_type_i, A* ) );
> > > +SA(   __is_invocable( memfun_type_i, A& ) );
> > > +SA(   __is_invocable( memfun_type_i, A&& ) );
> > > +SA( ! __is_invocable( memfun_type_i, const A& ) );
> > > +SA( ! __is_invocable( memfun_type_i, A&, int ) );
> > > +
> > > +using memfun_type_ic = int (A::*)() const;
> > > +
> > > +SA( ! __is_invocable( memfun_type_ic ) );
> > > +SA( ! __is_invocable( memfun_type_ic, int ) );
> > > +SA( ! __is_invocable( memfun_type_ic, int& ) );
> > > +SA(   __is_invocable( memfun_type_ic, A& ) );
> > > +SA(   __is_invocable( memfun_type_ic, A* ) );
> > > +SA( ! __is_invocable( memfun_type_ic, A&, int ) );
> > > +SA( ! __is_invocable( memfun_type_ic, A*, int& ) );
> > > +SA(   __is_invocable( memfun_type_ic, const A& ) );
> > > +SA(   __is_invocable( memfun_type_ic, const A* ) );
> > > +SA( ! __is_invocable( memfun_type_ic, const A&, int& ) );
> > > +SA( ! __is_invocable( memfun_type_ic, const A*, int ) );
> > > +
> > > +using memfun_type_iic = int& (A::*)(int&) const;
> > > +
> > > +SA( ! __is_invocable( memfun_type_iic ) );
> > > +SA( ! __is_invocable( memfun_type_iic, int ) );
> > > +SA( ! __is_invocable( memfun_type_iic, int& ) );
> > > +SA( ! __is_invocable( memfun_type_iic, A&, int ) );
> > > +SA(   __is_invocable( memfun_type_iic, A&, int& ) );
> > > +SA( ! __is_invocable( memfun_type_iic, A*, int ) );
> > > +SA(   __is_invocable( memfun_type_iic, A*, int& ) );
> > > +SA( ! __is_invocable( memfun_type_iic, const A&, int ) );
> > > +SA( ! __is_invocable( memfun_type_iic, const A&, int&, int ) );
> > > +SA(   __is_invocable( memfun_type_iic, const A&, int& ) );
> > > +SA(   __is_invocable( memfun_type_iic, const A*, int& ) );
> > > +
> > > +struct B {
> > > +  int& operator()();
> > > +  long& operator()() const;
> > > +  bool& operator()(int);
> > > +private:
> > > +  void operator()(int, int);
> > > +};
> > > +using CB = const B;
> > > +
> > > +SA(   __is_invocable( B ) );
> > > +SA(   __is_invocable( B& ) );
> > > +SA(   __is_invocable( B&& ) );
> > > +SA( ! __is_invocable( B* ) );
> > > +SA(   __is_invocable( CB ) );
> > > +SA(   __is_invocable( CB& ) );
> > > +SA( ! __is_invocable( CB* ) );
> > > +
> > > +SA(   __is_invocable( B, int ) );
> > > +SA(   __is_invocable( B&, int ) );
> > > +SA(   __is_invocable( B&&, int ) );
> > > +SA( ! __is_invocable( B*, int ) );
> > > +SA( ! __is_invocable( CB, int ) );
> > > +SA( ! __is_invocable( CB&, int ) );
> > > +SA( ! __is_invocable( CB*, int ) );
> > > +
> > > +SA( ! __is_invocable( B, int, int ) );
> > > +SA( ! __is_invocable( B&, int, int ) );
> > > +SA( ! __is_invocable( B&&, int, int ) );
> > > +SA( ! __is_invocable( B*, int, int ) );
> > > +SA( ! __is_invocable( CB, int, int ) );
> > > +SA( ! __is_invocable( CB&, int, int ) );
> > > +SA( ! __is_invocable( CB*, int, int ) );
> > > +
> > > +struct C : B { int& operator()() = delete; };
> > > +using CC = const C;
> > > +
> > > +SA( ! __is_invocable( C ) );
> > > +SA( ! __is_invocable( C& ) );
> > > +SA( ! __is_invocable( C&& ) );
> > > +SA( ! __is_invocable( C* ) );
> > > +SA( ! __is_invocable( CC ) );
> > > +SA( ! __is_invocable( CC& ) );
> > > +SA( ! __is_invocable( CC* ) );
> > > +
> > > +struct D { B operator*(); };
> > > +using CD = const D;
> > > +
> > > +SA( ! __is_invocable( D ) );
> > > +
> > > +struct E { void v(); };
> > > +using CE = const E;
> > > +
> > > +SA( ! __is_invocable( E ) );
> > > +SA( ! __is_invocable( void (E::*)() ) );
> > > +SA(   __is_invocable( void (E::*)(), E ) );
> > > +SA(   __is_invocable( void (E::*)(), E* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CE ) );
> > > +
> > > +struct F : E {};
> > > +using CF = const F;
> > > +
> > > +SA( ! __is_invocable( F ) );
> > > +SA(   __is_invocable( void (E::*)(), F ) );
> > > +SA(   __is_invocable( void (E::*)(), F* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CF ) );
> > > +
> > > +struct G { E operator*(); };
> > > +using CG = const G;
> > > +
> > > +SA( ! __is_invocable( G ) );
> > > +SA(   __is_invocable( void (E::*)(), G ) );
> > > +SA( ! __is_invocable( void (E::*)(), G* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CG ) );
> > > +
> > > +struct H { E& operator*(); };
> > > +using CH = const H;
> > > +
> > > +SA( ! __is_invocable( H ) );
> > > +SA(   __is_invocable( void (E::*)(), H ) );
> > > +SA( ! __is_invocable( void (E::*)(), H* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CH ) );
> > > +
> > > +struct I { E&& operator*(); };
> > > +using CI = const I;
> > > +
> > > +SA( ! __is_invocable( I ) );
> > > +SA(   __is_invocable( void (E::*)(), I ) );
> > > +SA( ! __is_invocable( void (E::*)(), I* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CI ) );
> > > +
> > > +struct K { E* operator*(); };
> > > +using CK = const K;
> > > +
> > > +SA( ! __is_invocable( K ) );
> > > +SA( ! __is_invocable( void (E::*)(), K ) );
> > > +SA( ! __is_invocable( void (E::*)(), K* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CK ) );
> > > +
> > > +struct L { CE operator*(); };
> > > +using CL = const L;
> > > +
> > > +SA( ! __is_invocable( L ) );
> > > +SA( ! __is_invocable( void (E::*)(), L ) );
> > > +SA( ! __is_invocable( void (E::*)(), L* ) );
> > > +SA( ! __is_invocable( void (E::*)(), CL ) );
> > > +
> > > +struct M {
> > > +  int i;
> > > +private:
> > > +  long l;
> > > +};
> > > +using CM = const M;
> > > +
> > > +SA( ! __is_invocable( M ) );
> > > +SA( ! __is_invocable( M& ) );
> > > +SA( ! __is_invocable( M&& ) );
> > > +SA( ! __is_invocable( M* ) );
> > > +SA( ! __is_invocable( CM ) );
> > > +SA( ! __is_invocable( CM& ) );
> > > +SA( ! __is_invocable( CM* ) );
> > > +
> > > +SA( ! __is_invocable( int M::* ) );
> > > +SA(   __is_invocable( int M::*, M ) );
> > > +SA(   __is_invocable( int M::*, M& ) );
> > > +SA(   __is_invocable( int M::*, M&& ) );
> > > +SA(   __is_invocable( int M::*, M* ) );
> > > +SA(   __is_invocable( int M::*, CM ) );
> > > +SA(   __is_invocable( int M::*, CM& ) );
> > > +SA(   __is_invocable( int M::*, CM* ) );
> > > +SA( ! __is_invocable( int M::*, int ) );
> > > +
> > > +SA( ! __is_invocable( int CM::* ) );
> > > +SA(   __is_invocable( int CM::*, M ) );
> > > +SA(   __is_invocable( int CM::*, M& ) );
> > > +SA(   __is_invocable( int CM::*, M&& ) );
> > > +SA(   __is_invocable( int CM::*, M* ) );
> > > +SA(   __is_invocable( int CM::*, CM ) );
> > > +SA(   __is_invocable( int CM::*, CM& ) );
> > > +SA(   __is_invocable( int CM::*, CM* ) );
> > > +SA( ! __is_invocable( int CM::*, int ) );
> > > +
> > > +SA( ! __is_invocable( long M::* ) );
> > > +SA(   __is_invocable( long M::*, M ) );
> > > +SA(   __is_invocable( long M::*, M& ) );
> > > +SA(   __is_invocable( long M::*, M&& ) );
> > > +SA(   __is_invocable( long M::*, M* ) );
> > > +SA(   __is_invocable( long M::*, CM ) );
> > > +SA(   __is_invocable( long M::*, CM& ) );
> > > +SA(   __is_invocable( long M::*, CM* ) );
> > > +SA( ! __is_invocable( long M::*, long ) );
> > > +
> > > +SA( ! __is_invocable( long CM::* ) );
> > > +SA(   __is_invocable( long CM::*, M ) );
> > > +SA(   __is_invocable( long CM::*, M& ) );
> > > +SA(   __is_invocable( long CM::*, M&& ) );
> > > +SA(   __is_invocable( long CM::*, M* ) );
> > > +SA(   __is_invocable( long CM::*, CM ) );
> > > +SA(   __is_invocable( long CM::*, CM& ) );
> > > +SA(   __is_invocable( long CM::*, CM* ) );
> > > +SA( ! __is_invocable( long CM::*, long ) );
> > > +
> > > +SA( ! __is_invocable( short M::* ) );
> > > +SA(   __is_invocable( short M::*, M ) );
> > > +SA(   __is_invocable( short M::*, M& ) );
> > > +SA(   __is_invocable( short M::*, M&& ) );
> > > +SA(   __is_invocable( short M::*, M* ) );
> > > +SA(   __is_invocable( short M::*, CM ) );
> > > +SA(   __is_invocable( short M::*, CM& ) );
> > > +SA(   __is_invocable( short M::*, CM* ) );
> > > +SA( ! __is_invocable( short M::*, short ) );
> > > +
> > > +SA( ! __is_invocable( short CM::* ) );
> > > +SA(   __is_invocable( short CM::*, M ) );
> > > +SA(   __is_invocable( short CM::*, M& ) );
> > > +SA(   __is_invocable( short CM::*, M&& ) );
> > > +SA(   __is_invocable( short CM::*, M* ) );
> > > +SA(   __is_invocable( short CM::*, CM ) );
> > > +SA(   __is_invocable( short CM::*, CM& ) );
> > > +SA(   __is_invocable( short CM::*, CM* ) );
> > > +SA( ! __is_invocable( short CM::*, short ) );
> > > +
> > > +struct N { M operator*(); };
> > > +SA(   __is_invocable( int M::*, N ) );
> > > +SA( ! __is_invocable( int M::*, N* ) );
> > > +
> > > +struct O { M& operator*(); };
> > > +SA(   __is_invocable( int M::*, O ) );
> > > +SA( ! __is_invocable( int M::*, O* ) );
> > > +
> > > +struct P { M&& operator*(); };
> > > +SA(   __is_invocable( int M::*, P ) );
> > > +SA( ! __is_invocable( int M::*, P* ) );
> > > +
> > > +struct Q { M* operator*(); };
> > > +SA( ! __is_invocable( int M::*, Q ) );
> > > +SA( ! __is_invocable( int M::*, Q* ) );
> > > +
> > > +struct R { void operator()(int = 0); };
> > > +
> > > +SA(   __is_invocable( R ) );
> > > +SA(   __is_invocable( R, int ) );
> > > +SA( ! __is_invocable( R, int, int ) );
> > > +
> > > +struct S { void operator()(int, ...); };
> > > +
> > > +SA( ! __is_invocable( S ) );
> > > +SA(   __is_invocable( S, int ) );
> > > +SA(   __is_invocable( S, int, int ) );
> > > +SA(   __is_invocable( S, int, int, int ) );
> > > +
> > > +void fn1() {}
> > > +
> > > +SA(   __is_invocable( decltype(fn1) ) );
> > > +
> > > +void fn2(int arr[10]);
> > > +
> > > +SA(   __is_invocable( decltype(fn2), int[10] ) );
> > > +SA(   __is_invocable( decltype(fn2), int(&)[10] ) );
> > > +SA(   __is_invocable( decltype(fn2), int(&&)[10] ) );
> > > +SA( ! __is_invocable( decltype(fn2), int(*)[10] ) );
> > > +SA( ! __is_invocable( decltype(fn2), int(*&)[10] ) );
> > > +SA( ! __is_invocable( decltype(fn2), int(*&&)[10] ) );
> > > +SA(   __is_invocable( decltype(fn2), int[] ) );
> > > +
> > > +auto lambda = []() {};
> > > +
> > > +SA(   __is_invocable( decltype(lambda) ) );
> > > +
> > > +template <typename Func, typename... Args>
> > > +struct can_invoke {
> > > +    static constexpr bool value = __is_invocable( Func, Args... );
> > > +};
> > > +
> > > +SA( can_invoke<decltype(lambda)>::value );
> > > +
> > > +struct T {
> > > +  void func() const {}
> > > +  int data;
> > > +};
> > > +
> > > +SA(   __is_invocable( decltype(&T::func)&, T& ) );
> > > +SA(   __is_invocable( decltype(&T::data)&, T& ) );
> > > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable2.C b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> > > new file mode 100644
> > > index 00000000000..a68aefd3e13
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/ext/is_invocable2.C
> > > @@ -0,0 +1,139 @@
> > > +// { dg-do compile { target c++11 } }
> > > +// __is_invocable should handle std::reference_wrapper correctly.
> > > +
> > > +#include <functional>
> > > +
> > > +#define SA(X) static_assert((X),#X)
> > > +
> > > +using std::reference_wrapper;
> > > +
> > > +using func_type_v0 = void(*)();
> > > +
> > > +SA(   __is_invocable( reference_wrapper<func_type_v0> ) );
> > > +SA( ! __is_invocable( reference_wrapper<func_type_v0>, int ) );
> > > +
> > > +using func_type_i0 = int(*)();
> > > +
> > > +SA(   __is_invocable( reference_wrapper<func_type_i0> ) );
> > > +SA( ! __is_invocable( reference_wrapper<func_type_i0>, int ) );
> > > +
> > > +using func_type_l0 = int&(*)();
> > > +
> > > +SA(   __is_invocable( reference_wrapper<func_type_l0> ) );
> > > +SA( ! __is_invocable( reference_wrapper<func_type_l0(int)> ) );
> > > +
> > > +using func_type_ii = int(*)(int);
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<func_type_ii> ) );
> > > +SA(   __is_invocable( reference_wrapper<func_type_ii>, int ) );
> > > +
> > > +using func_type_il = int(*)(int&);
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<func_type_il> ) );
> > > +SA( ! __is_invocable( reference_wrapper<func_type_il>, int ) );
> > > +SA(   __is_invocable( reference_wrapper<func_type_il>, int& ) );
> > > +
> > > +using func_type_ir = int(*)(int&&);
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<func_type_ir> ) );
> > > +SA( ! __is_invocable( reference_wrapper<func_type_ir>, int& ) );
> > > +SA(   __is_invocable( reference_wrapper<func_type_ir>, int ) );
> > > +SA(   __is_invocable( reference_wrapper<func_type_ir>, int&& ) );
> > > +
> > > +struct A { };
> > > +
> > > +using mem_type_i = int A::*;
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<mem_type_i> ) );
> > > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int* ) );
> > > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<mem_type_i>, int&& ) );
> > > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A ) );
> > > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A* ) );
> > > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A& ) );
> > > +SA(   __is_invocable( reference_wrapper<mem_type_i>, A&& ) );
> > > +
> > > +using memfun_type_i = int (A::*)();
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i> ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int* ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int&& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A* ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_i>, A&& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, const A& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_i>, A&, int ) );
> > > +
> > > +using memfun_type_ic = int (A::*)() const;
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic> ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A* ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A&, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A*, int& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A* ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A&, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A*, int ) );
> > > +
> > > +using memfun_type_iic = int& (A::*)(int&) const;
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic> ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A&, int ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A&, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A*, int ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A*, int& ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int&, int ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int& ) );
> > > +SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A*, int& ) );
> > > +
> > > +struct B {
> > > +  int& operator()();
> > > +  long& operator()() const;
> > > +  bool& operator()(int);
> > > +private:
> > > +  void operator()(int, int);
> > > +};
> > > +using CB = const B;
> > > +
> > > +SA(   __is_invocable( reference_wrapper<B> ) );
> > > +SA(   __is_invocable( reference_wrapper<B>& ) );
> > > +SA(   __is_invocable( reference_wrapper<B>&& ) );
> > > +SA(   __is_invocable( reference_wrapper<CB> ) );
> > > +SA(   __is_invocable( reference_wrapper<CB>& ) );
> > > +SA(   __is_invocable( reference_wrapper<B>, int ) );
> > > +SA( ! __is_invocable( reference_wrapper<B>&, int, int ) );
> > > +
> > > +struct C : B { int& operator()() = delete; };
> > > +using CC = const C;
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<C> ) );
> > > +SA( ! __is_invocable( reference_wrapper<C>& ) );
> > > +SA( ! __is_invocable( reference_wrapper<C>&& ) );
> > > +SA( ! __is_invocable( reference_wrapper<CC> ) );
> > > +SA( ! __is_invocable( reference_wrapper<CC>& ) );
> > > +
> > > +struct D { B operator*(); };
> > > +using CD = const D;
> > > +
> > > +SA( ! __is_invocable( reference_wrapper<D> ) );
> > > +SA( ! __is_invocable( reference_wrapper<D>& ) );
> > > +SA( ! __is_invocable( reference_wrapper<D>&& ) );
> > > +SA( ! __is_invocable( reference_wrapper<D>* ) );
> > > +SA( ! __is_invocable( reference_wrapper<D*> ) );
> > > +SA( ! __is_invocable( reference_wrapper<D*>* ) );
> > > +
> > > +std::function<void()> fn = []() {};
> > > +auto refwrap = std::ref(fn);
> > > +
> > > +SA(   __is_invocable( decltype(fn) ) );
> > > +SA(   __is_invocable( decltype(refwrap) ) );
> > > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable3.C b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> > > new file mode 100644
> > > index 00000000000..e2b0c5ef406
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/ext/is_invocable3.C
> > > @@ -0,0 +1,51 @@
> > > +// { dg-do compile { target c++11 } }
> > > +// __is_invocable should handle incomplete class correctly.
> > > +
> > > +#define SA(X) static_assert((X),#X)
> > > +
> > > +struct Incomplete;
> > > +
> > > +SA( ! __is_invocable( Incomplete ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( Incomplete, int ) ); // { dg-error "incomplete type" }
> > > +
> > > +SA( ! __is_invocable( int, Incomplete, int ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( int, Incomplete ) ); // { dg-error "incomplete type" }
> > > +
> > > +SA( ! __is_invocable( Incomplete, Incomplete() ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( Incomplete, Incomplete(int), int ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( Incomplete, Incomplete(int, int), int, int ) ); // { dg-error "incomplete type" }
> > > +
> > > +SA( ! __is_invocable( Incomplete, Incomplete(), int, int ) ); // { dg-error "incomplete type" }
> > > +
> > > +SA( ! __is_invocable( int(Incomplete), Incomplete ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( int(int, Incomplete), int, Incomplete ) ); // { dg-error "incomplete type" }
> > > +SA( ! __is_invocable( int(int, Incomplete), Incomplete, int ) ); // { dg-error "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int(Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( int(int, Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int(Incomplete&&), Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( int(int, Incomplete&&), int, Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int(const Incomplete&&), const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( int(int, const Incomplete&&), int, const Incomplete&& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int(const Incomplete&), const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( int(int, const Incomplete&), int, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int(const Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( int(int, const Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +SA(   __is_invocable( int Incomplete::*, const Incomplete& ) ); // { dg-bogus "incomplete type" }
> > > +SA( ! __is_invocable( void (Incomplete::*)(long&), const Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> > > +SA(   __is_invocable( void (Incomplete::*)(long&) const, Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +template <typename T>
> > > +struct Holder { T t; };
> > > +
> > > +SA(   __is_invocable( int(Holder<Incomplete>&), Holder<Incomplete>& ) ); // { dg-bogus "incomplete type" }
> > > +
> > > +// Define Incomplete, which is now not incomplete.
> > > +struct Incomplete { void operator()(); };
> > > +
> > > +SA( __is_invocable( Incomplete ) ); // { dg-bogus "incomplete type" }
> > > diff --git a/gcc/testsuite/g++.dg/ext/is_invocable4.C b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> > > new file mode 100644
> > > index 00000000000..d1efccf08f8
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/ext/is_invocable4.C
> > > @@ -0,0 +1,33 @@
> > > +// { dg-do compile { target c++11 } }
> > > +// Failed access check should be a substitution failure, not an error.
> > > +
> > > +#define SA(X) static_assert((X),#X)
> > > +
> > > +template<bool B>
> > > +struct bool_constant { static constexpr bool value = B; };
> > > +
> > > +template<typename _Fn, typename... _ArgTypes>
> > > +struct is_invocable
> > > +: public bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> > > +{ };
> > > +
> > > +#if __cpp_variable_templates
> > > +template<typename _Fn, typename... _ArgTypes>
> > > +constexpr bool is_invocable_v = __is_invocable(_Fn, _ArgTypes...);
> > > +#endif
> > > +
> > > +class Private
> > > +{
> > > +  void operator()() const
> > > +  {
> > > +    SA( ! is_invocable<Private>::value );
> > > +#if __cpp_variable_templates
> > > +    SA( ! is_invocable_v<Private> );
> > > +#endif
> > > +  }
> > > +};
> > > +
> > > +SA( ! is_invocable<Private>::value );
> > > +#if __cpp_variable_templates
> > > +SA( ! is_invocable_v<Private> );
> > > +#endif
> > > -- 
> > > 2.42.0
> > > 
> > > 
> > 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-20 13:53                       ` [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
@ 2023-10-22 12:06                         ` Ken Matsui
  2023-10-23 17:00                           ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-22 12:06 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, libstdc++, Ken Matsui, Jonathan Wakely

Hi Patrick,

There is an issue with the code in
libstdc++-v3/include/bits/cpp_type_traits.h. Specifically, Clang 16
does not accept the code, while Clang 17 does. Given that we aim to
support the last two versions of Clang, we need to ensure that Clang
16 accepts this code. Can you please advise on the best course of
action regarding this matter?

https://godbolt.org/z/PbxhYcb7q

Sincerely,
Ken Matsui

On Fri, Oct 20, 2023 at 7:12 AM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>
> This patch optimizes the compilation performance of std::is_pointer
> by dispatching to the new __is_pointer built-in trait.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
>         built-in trait.
>         * include/std/type_traits (is_pointer): Likewise. Optimize its
>         implementation.
>         (is_pointer_v): Likewise.
>
> Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
>  libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
>  2 files changed, 44 insertions(+), 8 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
> index 4312f32a4e0..246f2cc0b17 100644
> --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>    //
>    // Pointer types
>    //
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +  template<typename _Tp>
> +    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> +    {
> +      enum { __value = __is_pointer(_Tp) };
> +    };
> +#else
>    template<typename _Tp>
>      struct __is_pointer
>      {
> @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
>        enum { __value = 1 };
>        typedef __true_type __type;
>      };
> +#endif
>
>    //
>    // An arithmetic type is an integer type or a floating point type
> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> index 0641ecfdf2b..75a94cb8d7e 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      : public true_type { };
>  #endif
>
> -  template<typename>
> -    struct __is_pointer_helper
> +  /// is_pointer
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +  template<typename _Tp>
> +    struct is_pointer
> +    : public __bool_constant<__is_pointer(_Tp)>
> +    { };
> +#else
> +  template<typename _Tp>
> +    struct is_pointer
>      : public false_type { };
>
>    template<typename _Tp>
> -    struct __is_pointer_helper<_Tp*>
> +    struct is_pointer<_Tp*>
>      : public true_type { };
>
> -  /// is_pointer
>    template<typename _Tp>
> -    struct is_pointer
> -    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> -    { };
> +    struct is_pointer<_Tp* const>
> +    : public true_type { };
> +
> +  template<typename _Tp>
> +    struct is_pointer<_Tp* volatile>
> +    : public true_type { };
> +
> +  template<typename _Tp>
> +    struct is_pointer<_Tp* const volatile>
> +    : public true_type { };
> +#endif
>
>    /// is_lvalue_reference
>    template<typename>
> @@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
>    inline constexpr bool is_array_v<_Tp[_Num]> = true;
>  #endif
>
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> +#else
>  template <typename _Tp>
> -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> +  inline constexpr bool is_pointer_v = false;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp*> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> +#endif
> +
>  template <typename _Tp>
>    inline constexpr bool is_lvalue_reference_v = false;
>  template <typename _Tp>
> --
> 2.42.0
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-22 12:06                         ` Ken Matsui
@ 2023-10-23 17:00                           ` Patrick Palka
  2023-10-23 17:12                             ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-23 17:00 UTC (permalink / raw)
  To: Ken Matsui
  Cc: Patrick Palka, gcc-patches, libstdc++, Ken Matsui, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 4709 bytes --]

On Sun, 22 Oct 2023, Ken Matsui wrote:

> Hi Patrick,
> 
> There is an issue with the code in
> libstdc++-v3/include/bits/cpp_type_traits.h. Specifically, Clang 16
> does not accept the code, while Clang 17 does. Given that we aim to
> support the last two versions of Clang, we need to ensure that Clang
> 16 accepts this code. Can you please advise on the best course of
> action regarding this matter?

The following workaround seems to make Clang happy:

    #include <type_traits>

    template<typename T, bool B = __is_pointer(T)>
    struct __is_pointer : std::bool_constant<B> { };

> 
> https://godbolt.org/z/PbxhYcb7q
> 
> Sincerely,
> Ken Matsui
> 
> On Fri, Oct 20, 2023 at 7:12 AM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
> >
> > This patch optimizes the compilation performance of std::is_pointer
> > by dispatching to the new __is_pointer built-in trait.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         * include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
> >         built-in trait.
> >         * include/std/type_traits (is_pointer): Likewise. Optimize its
> >         implementation.
> >         (is_pointer_v): Likewise.
> >
> > Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
> >  libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
> >  2 files changed, 44 insertions(+), 8 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
> > index 4312f32a4e0..246f2cc0b17 100644
> > --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> > +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> > @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >    //
> >    // Pointer types
> >    //
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +  template<typename _Tp>
> > +    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> > +    {
> > +      enum { __value = __is_pointer(_Tp) };
> > +    };
> > +#else
> >    template<typename _Tp>
> >      struct __is_pointer
> >      {
> > @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> >        enum { __value = 1 };
> >        typedef __true_type __type;
> >      };
> > +#endif
> >
> >    //
> >    // An arithmetic type is an integer type or a floating point type
> > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> > index 0641ecfdf2b..75a94cb8d7e 100644
> > --- a/libstdc++-v3/include/std/type_traits
> > +++ b/libstdc++-v3/include/std/type_traits
> > @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >      : public true_type { };
> >  #endif
> >
> > -  template<typename>
> > -    struct __is_pointer_helper
> > +  /// is_pointer
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +  template<typename _Tp>
> > +    struct is_pointer
> > +    : public __bool_constant<__is_pointer(_Tp)>
> > +    { };
> > +#else
> > +  template<typename _Tp>
> > +    struct is_pointer
> >      : public false_type { };
> >
> >    template<typename _Tp>
> > -    struct __is_pointer_helper<_Tp*>
> > +    struct is_pointer<_Tp*>
> >      : public true_type { };
> >
> > -  /// is_pointer
> >    template<typename _Tp>
> > -    struct is_pointer
> > -    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> > -    { };
> > +    struct is_pointer<_Tp* const>
> > +    : public true_type { };
> > +
> > +  template<typename _Tp>
> > +    struct is_pointer<_Tp* volatile>
> > +    : public true_type { };
> > +
> > +  template<typename _Tp>
> > +    struct is_pointer<_Tp* const volatile>
> > +    : public true_type { };
> > +#endif
> >
> >    /// is_lvalue_reference
> >    template<typename>
> > @@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
> >    inline constexpr bool is_array_v<_Tp[_Num]> = true;
> >  #endif
> >
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> > +#else
> >  template <typename _Tp>
> > -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> > +  inline constexpr bool is_pointer_v = false;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp*> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> > +template <typename _Tp>
> > +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> > +#endif
> > +
> >  template <typename _Tp>
> >    inline constexpr bool is_lvalue_reference_v = false;
> >  template <typename _Tp>
> > --
> > 2.42.0
> >
> 
> 

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-20 16:17                         ` [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
@ 2023-10-23 17:04                           ` Patrick Palka
  2023-10-23 17:14                             ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-23 17:04 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>
> This patch optimizes the compilation performance of std::is_invocable
> by dispatching to the new __is_invocable built-in trait.
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/type_traits (is_invocable): Use __is_invocable
>         built-in trait.

Nice!  We should use the trait directly in is_invocable_v too.

>         * testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
>         the new error from __is_invocable.
>         * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
>  libstdc++-v3/include/std/type_traits                        | 6 ++++++
>  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
>  .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
>  3 files changed, 8 insertions(+)
>
> diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> index 75a94cb8d7e..91851b78c7e 100644
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
>
>    /// std::is_invocable
> +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
> +  template<typename _Fn, typename... _ArgTypes>
> +    struct is_invocable
> +    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> +#else
>    template<typename _Fn, typename... _ArgTypes>
>      struct is_invocable
>      : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
> +#endif
>      {
>        static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
>         "_Fn must be a complete class or an unbounded array");
> diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> index 34d1d9431d1..3f9e5274f3c 100644
> --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> @@ -18,6 +18,7 @@
>  // <http://www.gnu.org/licenses/>.
>
>  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> +// { dg-prune-output "invalid use of incomplete type" }
>
>  #include <type_traits>
>
> diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> index e1e54d25ee5..92af48c48b6 100644
> --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> @@ -18,6 +18,7 @@
>  // <http://www.gnu.org/licenses/>.
>
>  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> +// { dg-prune-output "invalid use of incomplete type" }
>
>  #include <type_traits>
>
> --
> 2.42.0
>


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-23 17:00                           ` Patrick Palka
@ 2023-10-23 17:12                             ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-23 17:12 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Jonathan Wakely, Ken Matsui, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 5260 bytes --]

On Mon, Oct 23, 2023 at 10:00 AM Patrick Palka <ppalka@redhat.com> wrote:

> On Sun, 22 Oct 2023, Ken Matsui wrote:
>
> > Hi Patrick,
> >
> > There is an issue with the code in
> > libstdc++-v3/include/bits/cpp_type_traits.h. Specifically, Clang 16
> > does not accept the code, while Clang 17 does. Given that we aim to
> > support the last two versions of Clang, we need to ensure that Clang
> > 16 accepts this code. Can you please advise on the best course of
> > action regarding this matter?
>
> The following workaround seems to make Clang happy:
>
>     #include <type_traits>
>
>     template<typename T, bool B = __is_pointer(T)>
>     struct __is_pointer : std::bool_constant<B> { };
>

Ooh, this makes sense. Thank you!


> >
> > https://godbolt.org/z/PbxhYcb7q
> >
> > Sincerely,
> > Ken Matsui
> >
> > On Fri, Oct 20, 2023 at 7:12 AM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
> > >
> > > This patch optimizes the compilation performance of std::is_pointer
> > > by dispatching to the new __is_pointer built-in trait.
> > >
> > > libstdc++-v3/ChangeLog:
> > >
> > >         * include/bits/cpp_type_traits.h (__is_pointer): Use
> __is_pointer
> > >         built-in trait.
> > >         * include/std/type_traits (is_pointer): Likewise. Optimize its
> > >         implementation.
> > >         (is_pointer_v): Likewise.
> > >
> > > Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > >  libstdc++-v3/include/bits/cpp_type_traits.h |  8 ++++
> > >  libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
> > >  2 files changed, 44 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h
> b/libstdc++-v3/include/bits/cpp_type_traits.h
> > > index 4312f32a4e0..246f2cc0b17 100644
> > > --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> > > +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> > > @@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> > >    //
> > >    // Pointer types
> > >    //
> > > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > > +  template<typename _Tp>
> > > +    struct __is_pointer : __truth_type<__is_pointer(_Tp)>
> > > +    {
> > > +      enum { __value = __is_pointer(_Tp) };
> > > +    };
> > > +#else
> > >    template<typename _Tp>
> > >      struct __is_pointer
> > >      {
> > > @@ -376,6 +383,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
> > >        enum { __value = 1 };
> > >        typedef __true_type __type;
> > >      };
> > > +#endif
> > >
> > >    //
> > >    // An arithmetic type is an integer type or a floating point type
> > > diff --git a/libstdc++-v3/include/std/type_traits
> b/libstdc++-v3/include/std/type_traits
> > > index 0641ecfdf2b..75a94cb8d7e 100644
> > > --- a/libstdc++-v3/include/std/type_traits
> > > +++ b/libstdc++-v3/include/std/type_traits
> > > @@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > >      : public true_type { };
> > >  #endif
> > >
> > > -  template<typename>
> > > -    struct __is_pointer_helper
> > > +  /// is_pointer
> > > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > > +  template<typename _Tp>
> > > +    struct is_pointer
> > > +    : public __bool_constant<__is_pointer(_Tp)>
> > > +    { };
> > > +#else
> > > +  template<typename _Tp>
> > > +    struct is_pointer
> > >      : public false_type { };
> > >
> > >    template<typename _Tp>
> > > -    struct __is_pointer_helper<_Tp*>
> > > +    struct is_pointer<_Tp*>
> > >      : public true_type { };
> > >
> > > -  /// is_pointer
> > >    template<typename _Tp>
> > > -    struct is_pointer
> > > -    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
> > > -    { };
> > > +    struct is_pointer<_Tp* const>
> > > +    : public true_type { };
> > > +
> > > +  template<typename _Tp>
> > > +    struct is_pointer<_Tp* volatile>
> > > +    : public true_type { };
> > > +
> > > +  template<typename _Tp>
> > > +    struct is_pointer<_Tp* const volatile>
> > > +    : public true_type { };
> > > +#endif
> > >
> > >    /// is_lvalue_reference
> > >    template<typename>
> > > @@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
> > >    inline constexpr bool is_array_v<_Tp[_Num]> = true;
> > >  #endif
> > >
> > > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
> > > +template <typename _Tp>
> > > +  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
> > > +#else
> > >  template <typename _Tp>
> > > -  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
> > > +  inline constexpr bool is_pointer_v = false;
> > > +template <typename _Tp>
> > > +  inline constexpr bool is_pointer_v<_Tp*> = true;
> > > +template <typename _Tp>
> > > +  inline constexpr bool is_pointer_v<_Tp* const> = true;
> > > +template <typename _Tp>
> > > +  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
> > > +template <typename _Tp>
> > > +  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
> > > +#endif
> > > +
> > >  template <typename _Tp>
> > >    inline constexpr bool is_lvalue_reference_v = false;
> > >  template <typename _Tp>
> > > --
> > > 2.42.0
> > >
> >
> >

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-23 17:04                           ` Patrick Palka
@ 2023-10-23 17:14                             ` Ken Matsui
  2023-10-23 17:38                               ` Patrick Palka
  0 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-23 17:14 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 3358 bytes --]

On Mon, Oct 23, 2023 at 10:05 AM Patrick Palka <ppalka@redhat.com> wrote:

> On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
> >
> > This patch optimizes the compilation performance of std::is_invocable
> > by dispatching to the new __is_invocable built-in trait.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         * include/std/type_traits (is_invocable): Use __is_invocable
> >         built-in trait.
>
> Nice!  We should use the trait directly in is_invocable_v too.
>

Thank you! But we want to take account of static_assert’s in is_invocable,
so I think we cannot use the built-in directly?


> >         * testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
> >         the new error from __is_invocable.
> >         * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
> >
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> >  libstdc++-v3/include/std/type_traits                        | 6 ++++++
> >  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
> >  .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
> >  3 files changed, 8 insertions(+)
> >
> > diff --git a/libstdc++-v3/include/std/type_traits
> b/libstdc++-v3/include/std/type_traits
> > index 75a94cb8d7e..91851b78c7e 100644
> > --- a/libstdc++-v3/include/std/type_traits
> > +++ b/libstdc++-v3/include/std/type_traits
> > @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >      using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
> >
> >    /// std::is_invocable
> > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
> > +  template<typename _Fn, typename... _ArgTypes>
> > +    struct is_invocable
> > +    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> > +#else
> >    template<typename _Fn, typename... _ArgTypes>
> >      struct is_invocable
> >      : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>,
> void>::type
> > +#endif
> >      {
> >
> static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
> >         "_Fn must be a complete class or an unbounded array");
> > diff --git
> a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> > index 34d1d9431d1..3f9e5274f3c 100644
> > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> > @@ -18,6 +18,7 @@
> >  // <http://www.gnu.org/licenses/>.
> >
> >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >  #include <type_traits>
> >
> > diff --git
> a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> > index e1e54d25ee5..92af48c48b6 100644
> > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> > @@ -18,6 +18,7 @@
> >  // <http://www.gnu.org/licenses/>.
> >
> >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> > +// { dg-prune-output "invalid use of incomplete type" }
> >
> >  #include <type_traits>
> >
> > --
> > 2.42.0
> >
>
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-23 17:14                             ` Ken Matsui
@ 2023-10-23 17:38                               ` Patrick Palka
  2023-10-23 17:47                                 ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-10-23 17:38 UTC (permalink / raw)
  To: Ken Matsui; +Cc: Patrick Palka, Ken Matsui, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 4212 bytes --]

On Mon, 23 Oct 2023, Ken Matsui wrote:

> On Mon, Oct 23, 2023 at 10:05 AM Patrick Palka <ppalka@redhat.com> wrote:
>       On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>       >
>       > This patch optimizes the compilation performance of std::is_invocable
>       > by dispatching to the new __is_invocable built-in trait.
>       >
>       > libstdc++-v3/ChangeLog:
>       >
>       >         * include/std/type_traits (is_invocable): Use __is_invocable
>       >         built-in trait.
> 
>       Nice!  We should use the trait directly in is_invocable_v too.
> 
> 
> Thank you! But we want to take account of static_assert’s in is_invocable, so I think we cannot use the built-in directly?

Good point, I guess that's a great reason to improvement the diagnostic
that check_trait_type emits: it'd speed up the class template version
because we could get rid of the static_asserts (without regressing
diagnostic quality), and it'd speed up the variable template version
because we could use the built-in directly there.

Your patch LGTM as is though, that could be a follow-up if anything.

> 
> 
>       >         * testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
>       >         the new error from __is_invocable.
>       >         * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
>       >
>       > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
>       > ---
>       >  libstdc++-v3/include/std/type_traits                        | 6 ++++++
>       >  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
>       >  .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
>       >  3 files changed, 8 insertions(+)
>       >
>       > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
>       > index 75a94cb8d7e..91851b78c7e 100644
>       > --- a/libstdc++-v3/include/std/type_traits
>       > +++ b/libstdc++-v3/include/std/type_traits
>       > @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>       >      using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
>       >
>       >    /// std::is_invocable
>       > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
>       > +  template<typename _Fn, typename... _ArgTypes>
>       > +    struct is_invocable
>       > +    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
>       > +#else
>       >    template<typename _Fn, typename... _ArgTypes>
>       >      struct is_invocable
>       >      : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
>       > +#endif
>       >      {
>       >        static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
>       >         "_Fn must be a complete class or an unbounded array");
>       > diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>       > index 34d1d9431d1..3f9e5274f3c 100644
>       > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>       > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
>       > @@ -18,6 +18,7 @@
>       >  // <http://www.gnu.org/licenses/>.
>       >
>       >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
>       > +// { dg-prune-output "invalid use of incomplete type" }
>       >
>       >  #include <type_traits>
>       >
>       > diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>       > index e1e54d25ee5..92af48c48b6 100644
>       > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>       > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
>       > @@ -18,6 +18,7 @@
>       >  // <http://www.gnu.org/licenses/>.
>       >
>       >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
>       > +// { dg-prune-output "invalid use of incomplete type" }
>       >
>       >  #include <type_traits>
>       >
>       > --
>       > 2.42.0
>       >
> 
> 
> 

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-23 17:38                               ` Patrick Palka
@ 2023-10-23 17:47                                 ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-23 17:47 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 23, 2023 at 10:39 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Mon, 23 Oct 2023, Ken Matsui wrote:
>
> > On Mon, Oct 23, 2023 at 10:05 AM Patrick Palka <ppalka@redhat.com> wrote:
> >       On Fri, Oct 20, 2023 at 12:22 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
> >       >
> >       > This patch optimizes the compilation performance of std::is_invocable
> >       > by dispatching to the new __is_invocable built-in trait.
> >       >
> >       > libstdc++-v3/ChangeLog:
> >       >
> >       >         * include/std/type_traits (is_invocable): Use __is_invocable
> >       >         built-in trait.
> >
> >       Nice!  We should use the trait directly in is_invocable_v too.
> >
> >
> > Thank you! But we want to take account of static_assert’s in is_invocable, so I think we cannot use the built-in directly?
>
> Good point, I guess that's a great reason to improvement the diagnostic
> that check_trait_type emits: it'd speed up the class template version
> because we could get rid of the static_asserts (without regressing
> diagnostic quality), and it'd speed up the variable template version
> because we could use the built-in directly there.
>
> Your patch LGTM as is though, that could be a follow-up if anything.
>

Thank you! I will also work on this after other built-in traits end!

> >
> >
> >       >         * testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
> >       >         the new error from __is_invocable.
> >       >         * testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.
> >       >
> >       > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> >       > ---
> >       >  libstdc++-v3/include/std/type_traits                        | 6 ++++++
> >       >  .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
> >       >  .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
> >       >  3 files changed, 8 insertions(+)
> >       >
> >       > diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
> >       > index 75a94cb8d7e..91851b78c7e 100644
> >       > --- a/libstdc++-v3/include/std/type_traits
> >       > +++ b/libstdc++-v3/include/std/type_traits
> >       > @@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >       >      using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
> >       >
> >       >    /// std::is_invocable
> >       > +#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
> >       > +  template<typename _Fn, typename... _ArgTypes>
> >       > +    struct is_invocable
> >       > +    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
> >       > +#else
> >       >    template<typename _Fn, typename... _ArgTypes>
> >       >      struct is_invocable
> >       >      : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
> >       > +#endif
> >       >      {
> >       >        static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
> >       >         "_Fn must be a complete class or an unbounded array");
> >       > diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> >       > index 34d1d9431d1..3f9e5274f3c 100644
> >       > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> >       > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
> >       > @@ -18,6 +18,7 @@
> >       >  // <http://www.gnu.org/licenses/>.
> >       >
> >       >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> >       > +// { dg-prune-output "invalid use of incomplete type" }
> >       >
> >       >  #include <type_traits>
> >       >
> >       > diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> >       > index e1e54d25ee5..92af48c48b6 100644
> >       > --- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> >       > +++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
> >       > @@ -18,6 +18,7 @@
> >       >  // <http://www.gnu.org/licenses/>.
> >       >
> >       >  // { dg-error "must be a complete class" "" { target *-*-* } 0 }
> >       > +// { dg-prune-output "invalid use of incomplete type" }
> >       >
> >       >  #include <type_traits>
> >       >
> >       > --
> >       > 2.42.0
> >       >
> >
> >
> >

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-20 13:53                       ` [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
  2023-10-20 19:11                         ` Patrick Palka
@ 2023-10-23 20:27                         ` Jason Merrill
  2023-10-23 21:08                           ` Ken Matsui
  1 sibling, 1 reply; 623+ messages in thread
From: Jason Merrill @ 2023-10-23 20:27 UTC (permalink / raw)
  To: Ken Matsui, gcc-patches; +Cc: libstdc++, Patrick Palka

On 10/20/23 09:53, Ken Matsui wrote:
> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in

These two lines are too long; please wrap at 75 columns so they don't go 
over 80 when git log adds 4 spaces at the beginning.

> traits and uses the identifier node to look up the specific trait.  Rather
> than holding traits as keywords, we set all trait identifiers as cik_trait,
> which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait.  Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.
> 
>   /* True if this identifier is for any operator name (including
> -   conversions).  Value 4, 5, 6 or 7.  */
> +   conversions).  Value 4, 5, or 6.  */
>   #define IDENTIFIER_ANY_OP_P(NODE)		\
> -  (IDENTIFIER_KIND_BIT_2 (NODE))
> +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
...
> +/* True if this identifier is the name of a built-in trait.  */
> +#define IDENTIFIER_TRAIT_P(NODE)		\
> +  (IDENTIFIER_KIND_BIT_0 (NODE)			\
> +   && IDENTIFIER_KIND_BIT_1 (NODE)		\
> +   && IDENTIFIER_KIND_BIT_2 (NODE))

The other macros use &, not &&; we might as well stay consistent with 
that pattern.

Jason


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers
  2023-10-20 13:53                       ` [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-23 20:36                         ` Jason Merrill
  2023-10-23 21:08                           ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Jason Merrill @ 2023-10-23 20:36 UTC (permalink / raw)
  To: Ken Matsui, gcc-patches; +Cc: libstdc++

On 10/20/23 09:53, Ken Matsui wrote:
> This patch accepts the use of built-in trait identifiers when they are
> actually not used as traits.  Specifically, we check if the subsequent token
> is '(' for ordinary built-in traits or is '<' only for the special
> __type_pack_element built-in trait.  If those identifiers are used
> differently, the parser treats them as normal identifiers.  This allows
> us to accept code like: struct __is_pointer {};.
> 
> +/* Peeks the corresponding built-in trait if a given token is
>      a built-in trait.  Otherwise, returns nullptr.  */
>   
>   static const cp_trait *
> +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)

Passing in both the lexer and the peeked token seems awkward, let's just 
pass in the lexer.  Looking up the peeked token again is fast.

>   {
> +  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
> +    {
> +      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
> +      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
> +
> +      /* Check if the subsequent token is a `<' token to
> +         __type_pack_element or is a `(' token to everything else.  */

git complains about indentation with spaces instead of a tab on this line.

Jason


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-23 20:27                         ` Jason Merrill
@ 2023-10-23 21:08                           ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-23 21:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Ken Matsui, gcc-patches, libstdc++, Patrick Palka

On Mon, Oct 23, 2023 at 1:27 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 10/20/23 09:53, Ken Matsui wrote:
> > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > once in a C++ translation unit, this patch removes all RID values for built-in
>
> These two lines are too long; please wrap at 75 columns so they don't go
> over 80 when git log adds 4 spaces at the beginning.
>
> > traits and uses the identifier node to look up the specific trait.  Rather
> > than holding traits as keywords, we set all trait identifiers as cik_trait,
> > which is a new cp_identifier_kind.  As cik_reserved_for_udlit was unused and
> > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > cik_trait.  Also, the later patch handles a subsequent token to the built-in
> > identifier so that we accept the use of non-function-like built-in trait
> > identifiers.
> >
> >   /* True if this identifier is for any operator name (including
> > -   conversions).  Value 4, 5, 6 or 7.  */
> > +   conversions).  Value 4, 5, or 6.  */
> >   #define IDENTIFIER_ANY_OP_P(NODE)           \
> > -  (IDENTIFIER_KIND_BIT_2 (NODE))
> > +  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> ...
> > +/* True if this identifier is the name of a built-in trait.  */
> > +#define IDENTIFIER_TRAIT_P(NODE)             \
> > +  (IDENTIFIER_KIND_BIT_0 (NODE)                      \
> > +   && IDENTIFIER_KIND_BIT_1 (NODE)           \
> > +   && IDENTIFIER_KIND_BIT_2 (NODE))
>
> The other macros use &, not &&; we might as well stay consistent with
> that pattern.
>

Thank you! Will fix these.

> Jason
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers
  2023-10-23 20:36                         ` Jason Merrill
@ 2023-10-23 21:08                           ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-23 21:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Ken Matsui, gcc-patches, libstdc++

On Mon, Oct 23, 2023 at 1:36 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 10/20/23 09:53, Ken Matsui wrote:
> > This patch accepts the use of built-in trait identifiers when they are
> > actually not used as traits.  Specifically, we check if the subsequent token
> > is '(' for ordinary built-in traits or is '<' only for the special
> > __type_pack_element built-in trait.  If those identifiers are used
> > differently, the parser treats them as normal identifiers.  This allows
> > us to accept code like: struct __is_pointer {};.
> >
> > +/* Peeks the corresponding built-in trait if a given token is
> >      a built-in trait.  Otherwise, returns nullptr.  */
> >
> >   static const cp_trait *
> > +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
>
> Passing in both the lexer and the peeked token seems awkward, let's just
> pass in the lexer.  Looking up the peeked token again is fast.
>
> >   {
> > +  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
> > +    {
> > +      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
> > +      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
> > +
> > +      /* Check if the subsequent token is a `<' token to
> > +         __type_pack_element or is a `(' token to everything else.  */
>
> git complains about indentation with spaces instead of a tab on this line.
>

Thank you!

> Jason
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-20 21:37                             ` Patrick Palka
@ 2023-10-23 21:23                               ` Jason Merrill
  2024-02-20  1:35                                 ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Jason Merrill @ 2023-10-23 21:23 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++, Patrick Palka

On 10/20/23 17:37, Patrick Palka wrote:
> On Fri, 20 Oct 2023, Patrick Palka wrote:
> 
>> On Fri, 20 Oct 2023, Patrick Palka wrote:
>>
>>> On Fri, 20 Oct 2023, Ken Matsui wrote:
>>>
>>>> This patch implements built-in trait for std::is_invocable.
>>>
>>> Nice!  My email client unfortunately ate my first review attempt, so
>>> apologies for my brevity this time around.
>>>
>>>> gcc/cp/ChangeLog:
>>>>
>>>> 	* cp-trait.def: Define __is_invocable.
>>>> 	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
>>>> 	* semantics.cc (trait_expr_value): Likewise.
>>>> 	(finish_trait_expr): Likewise.
>>>> 	(is_invocable_p): New function.
>>>> 	* method.h: New file to export build_trait_object in method.cc.

Given how much larger semantics.cc is than method.cc, maybe let's put 
is_invocable_p in method.cc instead?  And in general declarations can go 
in cp-tree.h.

>>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
>>>> index 7cccbae5287..cc2e400531a 100644
>>>> --- a/gcc/cp/semantics.cc
>>>> +++ b/gcc/cp/semantics.cc
>>>> @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
>>>>   #include "gomp-constants.h"
>>>>   #include "predict.h"
>>>>   #include "memmodel.h"
>>>> +#include "method.h"
>>>> +
>>>> +#include "print-tree.h"
>>>> +#include "tree-pretty-print.h"
>>>>   
>>>>   /* There routines provide a modular interface to perform many parsing
>>>>      operations.  They may therefore be used during actual parsing, or
>>>> @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
>>>>     return saw_copy;
>>>>   }
>>>>   
>>>> +/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
>>>> +
>>>> +static bool
>>>> +is_invocable_p (tree fn_type, tree arg_types)
> 
> (Sorry for the spam)  We'll eventually want to implement a built-in for
> invoke_result, so perhaps we should preemptively factor out the bulk
> of this function into a 'build_INVOKE' helper function that returns the
> built tree?
> 
>>>> +{
>>>> +  /* ARG_TYPES must be a TREE_VEC.  */
>>>> +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
>>>> +
>>>> +  /* Access check is required to determine if the given is invocable.  */
>>>> +  deferring_access_check_sentinel acs (dk_no_deferred);
>>>> +
>>>> +  /* std::is_invocable is an unevaluated context.  */
>>>> +  cp_unevaluated cp_uneval_guard;
>>>> +
>>>> +  bool is_ptrdatamem;
>>>> +  bool is_ptrmemfunc;
>>>> +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
>>>> +    {
>>>> +      tree deref_fn_type = TREE_TYPE (fn_type);
>>>> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
>>>> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
>>>> +
>>>> +      /* Dereference fn_type if it is a pointer to member.  */
>>>> +      if (is_ptrdatamem || is_ptrmemfunc)
>>>> +	fn_type = deref_fn_type;
>>>> +    }
>>>> +  else
>>>> +    {
>>>> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
>>>> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
>>>> +    }
>>>> +
>>>> +  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
>>>> +    /* A pointer to data member with non-one argument is not invocable.  */
>>>> +    return false;
>>>> +
>>>> +  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
>>>> +    /* A pointer to member function with no arguments is not invocable.  */
>>>> +    return false;
>>>> +
>>>> +  /* Construct an expression of a pointer to member.  */
>>>> +  tree datum;
>>>> +  if (is_ptrdatamem || is_ptrmemfunc)
>>>> +    {
>>>> +      tree datum_type = TREE_VEC_ELT (arg_types, 0);
>>>> +
>>>> +      /* Dereference datum.  */
>>>> +      if (CLASS_TYPE_P (datum_type))
>>>> +	{
>>>> +	  bool is_refwrap = false;
>>>> +
>>>> +	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
>>>> +	  if (decl_in_std_namespace_p (datum_decl))
>>>> +	    {
>>>> +	      tree name = DECL_NAME (datum_decl);
>>>> +	      if (name && (id_equal (name, "reference_wrapper")))
>>>> +		{
>>>> +		  /* Handle std::reference_wrapper.  */
>>>> +		  is_refwrap = true;
>>>> +		  datum_type = cp_build_reference_type (datum_type, false);

Why do you change datum_type from std::reference_wrapper<...> to 
std::reference_wrapper<...>&?

>>>> +		}
>>>> +	    }
>>>> +
>>>> +	  datum = build_trait_object (datum_type);
>>>> +
>>>> +	  /* If datum_type was not std::reference_wrapper, check if it has
>>>> +	     operator*() overload.  If datum_type was std::reference_wrapper,
>>>> +	     avoid dereferencing the datum twice.  */
>>>> +	  if (!is_refwrap)
>>>> +	    if (get_class_binding (datum_type, get_identifier ("operator*")))
>>>
>>> We probably should use lookup_member instead of get_class_binding since
>>> IIUC the latter doesn't look into bases:
>>>
>>>    struct A { int m; };
>>>    struct B { A& operator*(): };
>>>    struct C : B { };
>>>    static_assert(std::is_invocable_v<int A::*, C>);
>>>
>>> However, I notice that the specification of INVOKE
>>> (https://eel.is/c++draft/func.require#lib:INVOKE) doesn't mention name
>>> lookup at all so it strikes me as suspicious that we'd perform name
>>> lookup here.

Agreed.  It seems that whether or not to build_x_indirect_ref should 
depend instead on whether f is a pointer to a member of decltype(t1) (as 
well as is_refwrap).

>>>  I think this would misbehave for:
>>>
>>>    struct A { };
>>>    struct B : A { A& operator*() = delete; };
>>>    static_assert(std::is_invocable_v<int A::*, B>);
>>>
>>>    struct C : private A { A& operator*(); };
>>>    static_assert(std::is_invocable_v<int A::*, C>);
>>
>> Oops, this static_assert is missing a !
>>
>>>
>>> ultimately because we end up choosing the dereference form of INVOKE,
>>> but according to 1.1/1.4 we should choose the non-dereference form?
>>>
>>>> +	      /* Handle operator*().  */
>>>> +	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
>>>> +					    RO_UNARY_STAR, NULL_TREE,
>>>> +					    tf_none);
>>>> +	}
>>>> +      else if (POINTER_TYPE_P (datum_type))
>>>> +	datum = build_trait_object (TREE_TYPE (datum_type));
>>>> +      else
>>>> +	datum = build_trait_object (datum_type);
>>>> +    }
>>>> +
>>>> +  /* Build a function expression.  */
>>>> +  tree fn;
>>>> +  if (is_ptrdatamem)
>>>> +    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
>>>
>>> Maybe exit early for the is_ptrdatamem case here (and simplify the rest
>>> of the function accordingly)?
>>>
>>>> +  else if (is_ptrmemfunc)
>>>> +    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));

Why not use build_m_component_ref and build_offset_ref_call_from_tree 
like it would if you wrote (t1.*f)() directly?

Jason


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 00/33] Optimize type traits compilation performance
  2023-10-20 16:16                       ` [PATCH v24 00/33] Optimize type traits performance Ken Matsui
  2023-10-20 16:17                         ` [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
@ 2023-10-24  2:00                         ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 01/33] c++: Sort built-in traits alphabetically Ken Matsui
                                             ` (35 more replies)
  1 sibling, 36 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits compilation performance by
implementing built-in type traits and using them in libstdc++.

Changes in v25:

	* Optimized the __is_pointer implementation in cpp_type_traits.h.
	* Fix compilation error in cpp_type_traits.h with Clang 16.
	* Wrapped commit messages at 75 columns.
	* Used & instead of && for the new IDENTIFIER_TRAIT_P macro.
	* Made cp_lexer_peek_trait not to take cp_token.
	* Fixed indentation error in cp_lexer_peek_trait.

Changes in v24:

	* Fixed the way to handle an incomplete type error from __is_invocable
	in the test cases so that we can correctly test both the use of
	built-in and vice-versa.

Changes in v23:

	* Improved the comment in cp-tree.h.
	* Moved the definition of cp_traits to lex.cc from parser.cc.
	* Implemented __is_invocable built-in trait.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (33):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_const built-in trait
  libstdc++: Optimize std::is_const compilation performance
  c++: Implement __is_volatile built-in trait
  libstdc++: Optimize std::is_volatile compilation performance
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_unbounded_array built-in trait
  libstdc++: Optimize std::is_unbounded_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance
  c++: Implement __is_pointer built-in trait
  libstdc++: Optimize std::is_pointer compilation performance
  c++: Implement __is_invocable built-in trait
  libstdc++: Optimize std::is_invocable compilation performance

 gcc/c-family/c-common.cc                      |   7 -
 gcc/c-family/c-common.h                       |   5 -
 gcc/cp/constraint.cc                          | 109 ++++--
 gcc/cp/cp-objcp-common.cc                     |   8 +-
 gcc/cp/cp-trait.def                           |  25 +-
 gcc/cp/cp-tree.h                              |  32 +-
 gcc/cp/lex.cc                                 |  34 ++
 gcc/cp/method.h                               |  28 ++
 gcc/cp/parser.cc                              | 120 ++++---
 gcc/cp/semantics.cc                           | 284 ++++++++++++---
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 113 ++++--
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++
 gcc/testsuite/g++.dg/ext/is_const.C           |  19 +
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++
 gcc/testsuite/g++.dg/ext/is_invocable1.C      | 337 ++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable2.C      | 139 ++++++++
 gcc/testsuite/g++.dg/ext/is_invocable3.C      |  51 +++
 gcc/testsuite/g++.dg/ext/is_invocable4.C      |  33 ++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
 gcc/testsuite/g++.dg/ext/is_object.C          |  29 ++
 gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 +++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 ++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
 gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++
 gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 +
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++
 libstdc++-v3/include/bits/cpp_type_traits.h   |  29 ++
 libstdc++-v3/include/std/type_traits          | 219 +++++++++++-
 .../is_invocable/incomplete_args_neg.cc       |   1 +
 .../20_util/is_invocable/incomplete_neg.cc    |   1 +
 33 files changed, 1901 insertions(+), 196 deletions(-)
 create mode 100644 gcc/cp/method.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 01/33] c++: Sort built-in traits alphabetically
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                             ` (34 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 64b64e17857..41fe2812ac4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3703,18 +3703,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3730,6 +3748,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3749,50 +3779,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 2a0cf963e91..144cb440fa3 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12090,15 +12090,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12107,17 +12098,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12131,18 +12131,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12151,6 +12154,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12166,6 +12175,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12196,24 +12214,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12326,9 +12326,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12348,12 +12348,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12372,8 +12372,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12436,25 +12436,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 02/33] c-family, c++: Look up built-in traits via identifier node
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 01/33] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
                                             ` (33 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used
approximately once in a C++ translation unit, this patch removes
all RID values for built-in traits and uses the identifier node to
look up the specific trait.  Rather than holding traits as keywords,
we set all trait identifiers as cik_trait, which is a new
cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the
built-in identifier so that we accept the use of non-function-like
built-in trait identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in
	traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (cp_traits): Define its values, declared in cp-tree.h.
	(init_cp_traits): New function to set cik_trait and
	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 ---
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  32 +++++++++---
 gcc/cp/lex.cc             |  34 ++++++++++++
 gcc/cp/parser.cc          | 105 +++++++++++++++++++++++---------------
 6 files changed, 126 insertions(+), 65 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index f044db5b797..21fd333ef57 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 1fdba7ef3ea..051a442e0f4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 93b027b80ce..b1adacfec07 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -421,6 +421,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -434,10 +438,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index efcd2de54e5..2087c9da6df 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   & IDENTIFIER_KIND_BIT_1 (NODE)		\
+   & IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1375,16 +1381,26 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  const char *name;
+  cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+
+/* The trait table indexed by cp_trait_kind.  */
+extern const struct cp_trait cp_traits[];
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..a939e2e5f13 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -97,6 +98,19 @@ ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
 unsigned char ovl_op_mapping[MAX_TREE_CODES];
 unsigned char ovl_op_alternate[OVL_OP_MAX];
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(ARRAY_SIZE (cp_traits) <= 255,
+	      "cp_traits array cannot have more than 255 entries");
+
 /* Get the name of the kind of identifier T.  */
 
 const char *
@@ -283,6 +297,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+  for (unsigned int i = 0; i < ARRAY_SIZE (cp_traits); ++i)
+    {
+      id = get_identifier (cp_traits[i].name);
+      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
+      set_identifier_kind (id, cik_trait);
+    }
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +357,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 59b9852895e..f87d4c0a855 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1167,12 +1173,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1182,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
+    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1190,6 +1228,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2854,7 +2894,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6029,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6073,6 +6107,9 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+	return cp_parser_trait (parser, trait);
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11041,28 +11078,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
+  const cp_trait_kind kind = trait->kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
+  const bool type = trait->type;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -20089,20 +20111,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 03/33] c++: Accept the use of built-in trait identifiers
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 01/33] c++: Sort built-in traits alphabetically Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 04/33] c++: Implement __is_const built-in trait Ken Matsui
                                             ` (32 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent
token is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 53 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f87d4c0a855..ed48ddfde17 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1182,15 +1182,29 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
-   a built-in trait.  Otherwise, returns nullptr.  */
+/* Peeks the corresponding built-in trait if the first token is
+   a built-in trait and the second token is either `(' or `<' depending
+   on the trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  const cp_token *token1 = cp_lexer_peek_token (lexer);
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+	 __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1198,9 +1212,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer);
   if (trait && !trait->type)
     return trait;
 
@@ -1211,9 +1225,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer);
   if (trait && trait->type)
     return trait;
 
@@ -1227,9 +1241,10 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
 {
   cp_token *token;
 
-  token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer))
     return true;
+
+  token = cp_lexer_peek_token (lexer);
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -6107,7 +6122,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20116,7 +20131,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 04/33] c++: Implement __is_const built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (2 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
                                             ` (31 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_const.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_const.
	* g++.dg/ext/is_const.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_const.C      | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41fe2812ac4..41d9eef7227 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONST:
+      inform (loc, "  %qT is not a const type", t1);
+      break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
     inform (loc, "  %qT is not default constructible", t1);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..9e4e6d798a0 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
+DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 144cb440fa3..7fbcfd7ccad 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONST:
+      return CP_TYPE_CONST_P (type1);
+
     case CPTK_IS_CONSTRUCTIBLE:
       return is_xible (INIT_EXPR, type1, type2);
 
@@ -12371,6 +12374,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CLASS:
+    case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..e6e481b13c5 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_const)
+# error "__has_builtin (__is_const) failed"
+#endif
 #if !__has_builtin (__is_constructible)
 # error "__has_builtin (__is_constructible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_const.C b/gcc/testsuite/g++.dg/ext/is_const.C
new file mode 100644
index 00000000000..8f2d7c2fce9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_const.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_const(const int));
+SA(__is_const(const volatile int));
+SA(__is_const(cClassType));
+SA(__is_const(cvClassType));
+
+// Negative tests.
+SA(!__is_const(int));
+SA(!__is_const(volatile int));
+SA(!__is_const(ClassType));
+SA(!__is_const(vClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 05/33] libstdc++: Optimize std::is_const compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (3 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 04/33] c++: Implement __is_const built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
                                             ` (30 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_const
by dispatching to the new __is_const built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_const): Use __is_const built-in
	trait.
	(is_const_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..686e38e47c3 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -784,6 +784,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Type properties.
 
   /// is_const
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+  template<typename _Tp>
+    struct is_const
+    : public __bool_constant<__is_const(_Tp)>
+    { };
+#else
   template<typename>
     struct is_const
     : public false_type { };
@@ -791,6 +797,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_const<_Tp const>
     : public true_type { };
+#endif
 
   /// is_volatile
   template<typename>
@@ -3218,10 +3225,17 @@ template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 06/33] c++: Implement __is_volatile built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (4 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
                                             ` (29 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_volatile.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_volatile.
	* g++.dg/ext/is_volatile.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_volatile.C   | 19 +++++++++++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 41d9eef7227..54782a167dd 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
+    case CPTK_IS_VOLATILE:
+      inform (loc, "  %qT is not a volatile type", t1);
+      break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
 	      "object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9e4e6d798a0..d786f47e60c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 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_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7fbcfd7ccad..7726fa99711 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
+    case CPTK_IS_VOLATILE:
+      return CP_TYPE_VOLATILE_P (type1);
+
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12378,6 +12381,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
     case CPTK_IS_UNION:
+    case CPTK_IS_VOLATILE:
       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 e6e481b13c5..fb03dd20e84 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
+#if !__has_builtin (__is_volatile)
+# error "__has_builtin (__is_volatile) failed"
+#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_volatile.C b/gcc/testsuite/g++.dg/ext/is_volatile.C
new file mode 100644
index 00000000000..004e397e5e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_volatile.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+// Positive tests.
+SA(__is_volatile(volatile int));
+SA(__is_volatile(const volatile int));
+SA(__is_volatile(vClassType));
+SA(__is_volatile(cvClassType));
+
+// Negative tests.
+SA(!__is_volatile(int));
+SA(!__is_volatile(const int));
+SA(!__is_volatile(ClassType));
+SA(!__is_volatile(cClassType));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 07/33] libstdc++: Optimize std::is_volatile compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (5 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 08/33] c++: Implement __is_array built-in trait Ken Matsui
                                             ` (28 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_volatile
by dispatching to the new __is_volatile built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_volatile): Use __is_volatile
	built-in trait.
	(is_volatile_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 686e38e47c3..c01f65df22b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -800,6 +800,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
   /// is_volatile
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+  template<typename _Tp>
+    struct is_volatile
+    : public __bool_constant<__is_volatile(_Tp)>
+    { };
+#else
   template<typename>
     struct is_volatile
     : public false_type { };
@@ -807,6 +813,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_volatile<_Tp volatile>
     : public true_type { };
+#endif
 
   /// is_trivial
   template<typename _Tp>
@@ -3236,10 +3243,15 @@ template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
+template <typename _Tp>
+  inline constexpr bool is_volatile_v = __is_volatile(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 08/33] c++: Implement __is_array built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (6 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
                                             ` (27 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 54782a167dd..b9f89fe178c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3715,6 +3715,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index d786f47e60c..99bc05360b9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7726fa99711..8d5874d6ab0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12143,6 +12143,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12376,6 +12379,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb03dd20e84..645cabe088e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 09/33] libstdc++: Optimize std::is_array compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (7 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 08/33] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
                                             ` (26 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_array
by dispatching to the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in
	trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index c01f65df22b..4e8165e5af5 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3183,12 +3190,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 10/33] c++: Implement __is_unbounded_array built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (8 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
                                             ` (25 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_unbounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_unbounded_array.
	* g++.dg/ext/is_unbounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_unbounded_array.C | 37 +++++++++++++++++++
 5 files changed, 48 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index b9f89fe178c..292b941e6a0 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3797,6 +3797,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       inform (loc, "  %qT is not trivially copyable", t1);
       break;
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      inform (loc, "  %qT is not an unbounded array", t1);
+      break;
     case CPTK_IS_UNION:
       inform (loc, "  %qT is not a union", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 99bc05360b9..4e02f68e4a9 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -83,6 +83,7 @@ DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
 DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
+DEFTRAIT_EXPR (IS_UNBOUNDED_ARRAY, "__is_unbounded_array", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 1)
 DEFTRAIT_EXPR (IS_VOLATILE, "__is_volatile", 1)
 DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8d5874d6ab0..bd73323e6db 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12217,6 +12217,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return trivially_copyable_p (type1);
 
+    case CPTK_IS_UNBOUNDED_ARRAY:
+      return array_of_unknown_bound_p (type1);
+
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
@@ -12384,6 +12387,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
       break;
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 645cabe088e..90997210c12 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -131,6 +131,9 @@
 #if !__has_builtin (__is_trivially_copyable)
 # error "__has_builtin (__is_trivially_copyable) failed"
 #endif
+#if !__has_builtin (__is_unbounded_array)
+# error "__has_builtin (__is_unbounded_array) failed"
+#endif
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_unbounded_array.C b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
new file mode 100644
index 00000000000..1307d24f5a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_unbounded_array.C
@@ -0,0 +1,37 @@
+// { 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_unbounded_array, int[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[2][3], false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass[][3], true);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[2], false);
+SA_TEST_CATEGORY(__is_unbounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_unbounded_array, ClassType, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_unbounded_array, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (9 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                             ` (24 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_unbounded_array by dispatching to the new
__is_unbounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_unbounded_array_v): Use
	__is_unbounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4e8165e5af5..cb3d9e238fa 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3541,11 +3541,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_unbounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v = false;
 
   template<typename _Tp>
     inline constexpr bool is_unbounded_array_v<_Tp[]> = true;
+# endif
 
   /// True for a type that is an array of known bound.
   /// @since C++20
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 12/33] c++: Implement __is_bounded_array built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (10 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
                                             ` (23 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 292b941e6a0..71a40558881 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3724,6 +3724,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 4e02f68e4a9..6d6dff7a4c3 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONST, "__is_const", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index bd73323e6db..aab35c9e5ba 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12154,6 +12154,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12383,6 +12386,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 90997210c12..4142da518b1 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 13/33] libstdc++: Optimize std::is_bounded_array compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (11 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                             ` (22 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_bounded_array
by dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use
	__is_bounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index cb3d9e238fa..d306073a797 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3532,11 +3532,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 14/33] c++: Implement __is_scoped_enum built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (12 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
                                             ` (21 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 71a40558881..2b46e3afa97 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3782,6 +3782,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 6d6dff7a4c3..e0e3fe1d23f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index aab35c9e5ba..9f0e468f489 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12391,6 +12394,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
     case CPTK_IS_UNION:
     case CPTK_IS_VOLATILE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4142da518b1..ba97beea3c3 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (13 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:00                           ` [PATCH v25 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                             ` (20 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_scoped_enum
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d306073a797..7fd29d8d9f2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3633,6 +3633,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3644,11 +3650,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 16/33] c++: Implement __is_member_pointer built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (14 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
@ 2023-10-24  2:00                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
                                             ` (19 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2b46e3afa97..a969a069db4 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e0e3fe1d23f..26087da3bdf 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9f0e468f489..5ca05dde75d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12393,6 +12396,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index ba97beea3c3..994873f14e9 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 17/33] libstdc++: Optimize std::is_member_pointer compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (15 preceding siblings ...)
  2023-10-24  2:00                           ` [PATCH v25 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                             ` (18 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_member_pointer
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use
	__is_member_pointer built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 7fd29d8d9f2..d7f89cf7c06 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3242,8 +3249,14 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 18/33] c++: Implement __is_member_function_pointer built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (16 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
                                             ` (17 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index a969a069db4..dde83533382 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_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 26087da3bdf..897b96630f2 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5ca05dde75d..59aaa256232 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12184,6 +12184,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12396,6 +12399,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 994873f14e9..0dfe957474b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (17 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                             ` (16 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_function_pointer by dispatching to the new
__is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index d7f89cf7c06..e1b10240dc2 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3222,9 +3230,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 20/33] c++: Implement __is_member_object_pointer built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (18 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
                                             ` (15 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index dde83533382..9db3a60943e 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3760,6 +3760,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 897b96630f2..11fd70b3964 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -73,6 +73,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 59aaa256232..c7e6396370d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12187,6 +12187,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12400,6 +12403,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 0dfe957474b..8d9cdc528cd 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -98,6 +98,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (19 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 22/33] c++: Implement __is_reference built-in trait Ken Matsui
                                             ` (14 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_object_pointer by dispatching to the new
__is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e1b10240dc2..792213ebfe8 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3227,9 +3235,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 22/33] c++: Implement __is_reference built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (20 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
                                             ` (13 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9db3a60943e..e05d4fa4d20 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3788,6 +3788,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 11fd70b3964..e867d9c4c47 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -81,6 +81,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c7e6396370d..cd17cd176cb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12211,6 +12211,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNBOUNDED_ARRAY:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 8d9cdc528cd..e112d317657 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -122,6 +122,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 23/33] libstdc++: Optimize std::is_reference compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (21 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 22/33] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 24/33] c++: Implement __is_function built-in trait Ken Matsui
                                             ` (12 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_reference
by dispatching to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference
	built-in trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 792213ebfe8..36ad9814047 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3264,12 +3271,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 24/33] c++: Implement __is_function built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (22 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
                                             ` (11 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index e05d4fa4d20..c394657d6b9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3751,6 +3751,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e867d9c4c47..fa79bc0c68c 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -70,6 +70,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cd17cd176cb..8118d3104c7 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12178,6 +12178,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12405,6 +12408,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_CONST:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index e112d317657..4d3947572a4 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -89,6 +89,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (23 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 24/33] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24 11:01                             ` Jonathan Wakely
  2023-10-24  2:01                           ` [PATCH v25 26/33] c++: Implement __is_object built-in trait Ken Matsui
                                             ` (10 subsequent siblings)
  35 siblings, 1 reply; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_function
by dispatching to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function
	built-in trait.
	(is_function_v): Likewise. Optimize its implementation.
	(is_const_v): Move on top of is_function_v as is_function_v now
	depends on is_const_v.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 39 ++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 36ad9814047..1e561c8ea38 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3269,8 +3276,28 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
+template <typename _Tp>
+  inline constexpr bool is_const_v = __is_const(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_const_v = false;
 template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+  inline constexpr bool is_const_v<const _Tp> = true;
+#endif
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+template <typename _Tp>
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
@@ -3303,16 +3330,6 @@ template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
 #endif
 
-#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_const)
-template <typename _Tp>
-  inline constexpr bool is_const_v = __is_const(_Tp);
-#else
-template <typename _Tp>
-  inline constexpr bool is_const_v = false;
-template <typename _Tp>
-  inline constexpr bool is_const_v<const _Tp> = true;
-#endif
-
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_volatile)
 template <typename _Tp>
   inline constexpr bool is_volatile_v = __is_volatile(_Tp);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 26/33] c++: Implement __is_object built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (24 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
                                             ` (9 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_object.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_object.
	* g++.dg/ext/is_object.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 +++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/semantics.cc                      |  6 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
 gcc/testsuite/g++.dg/ext/is_object.C     | 29 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c394657d6b9..444dbaacd78 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3781,6 +3781,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
 	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
+    case CPTK_IS_OBJECT:
+      inform (loc, "  %qT is not an object type", t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index fa79bc0c68c..191a86307fc 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -79,6 +79,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8118d3104c7..e3f71ff5902 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12205,6 +12205,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
       return is_nothrow_convertible (type1, type2);
 
+    case CPTK_IS_OBJECT:
+      return (type_code1 != FUNCTION_TYPE
+	      && type_code1 != REFERENCE_TYPE
+	      && type_code1 != VOID_TYPE);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12412,6 +12417,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_OBJECT:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4d3947572a4..163be1d710b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -116,6 +116,9 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__is_object)
+# error "__has_builtin (__is_object) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_object.C b/gcc/testsuite/g++.dg/ext/is_object.C
new file mode 100644
index 00000000000..5c759a5ef69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_object.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);				\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_NON_VOLATILE(__is_object, int (int), false);
+SA_TEST_NON_VOLATILE(__is_object, ClassType (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_object,
+		     float (int, float, int[], int&), false);
+SA_TEST_CATEGORY(__is_object, int&, false);
+SA_TEST_CATEGORY(__is_object, ClassType&, false);
+SA_TEST_NON_VOLATILE(__is_object, int(&)(int), false);
+SA_TEST_CATEGORY(__is_object, void, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_object, ClassType, true);
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 27/33] libstdc++: Optimize std::is_object compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (25 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 26/33] c++: Implement __is_object built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
                                             ` (8 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_object
by dispatching to the new __is_object built-in trait.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_object built-in
	trait.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 1e561c8ea38..80ec0fd5475 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<__is_object(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3315,8 +3322,15 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+template <typename _Tp>
+  inline constexpr bool is_object_v = __is_object(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 28/33] c++: Implement __remove_pointer built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (26 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
                                             ` (7 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 191a86307fc..1f405f61861 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -98,6 +98,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e3f71ff5902..45584e9045f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12494,6 +12494,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 163be1d710b..719902d3f1a 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -176,6 +176,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 29/33] libstdc++: Optimize std::remove_pointer compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (27 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
                                             ` (6 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::remove_pointer
by dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 80ec0fd5475..0641ecfdf2b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2103,6 +2103,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2111,11 +2117,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 30/33] c++: Implement __is_pointer built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (28 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
                                             ` (5 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_pointer.
	* g++.dg/ext/is_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_pointer.C    | 51 ++++++++++++++++++++++++
 5 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 444dbaacd78..9fce36e12d1 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3791,6 +3791,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POD:
       inform (loc, "  %qT is not a POD type", t1);
       break;
+    case CPTK_IS_POINTER:
+      inform (loc, "  %qT is not a pointer", t1);
+      break;
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 1f405f61861..05514a51c21 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -82,6 +82,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
+DEFTRAIT_EXPR (IS_POINTER, "__is_pointer", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 45584e9045f..7cccbae5287 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12216,6 +12216,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POD:
       return pod_type_p (type1);
 
+    case CPTK_IS_POINTER:
+      return TYPE_PTR_P (type1);
+
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
@@ -12418,6 +12421,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_OBJECT:
+    case CPTK_IS_POINTER:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 719902d3f1a..b1430e9bd8b 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -125,6 +125,9 @@
 #if !__has_builtin (__is_pod)
 # error "__has_builtin (__is_pod) failed"
 #endif
+#if !__has_builtin (__is_pointer)
+# error "__has_builtin (__is_pointer) failed"
+#endif
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_pointer.C b/gcc/testsuite/g++.dg/ext/is_pointer.C
new file mode 100644
index 00000000000..d6e39565950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(!__is_pointer(int));
+SA(__is_pointer(int*));
+SA(__is_pointer(int**));
+
+SA(__is_pointer(const int*));
+SA(__is_pointer(const int**));
+SA(__is_pointer(int* const));
+SA(__is_pointer(int** const));
+SA(__is_pointer(int* const* const));
+
+SA(__is_pointer(volatile int*));
+SA(__is_pointer(volatile int**));
+SA(__is_pointer(int* volatile));
+SA(__is_pointer(int** volatile));
+SA(__is_pointer(int* volatile* volatile));
+
+SA(__is_pointer(const volatile int*));
+SA(__is_pointer(const volatile int**));
+SA(__is_pointer(const int* volatile));
+SA(__is_pointer(volatile int* const));
+SA(__is_pointer(int* const volatile));
+SA(__is_pointer(const int** volatile));
+SA(__is_pointer(volatile int** const));
+SA(__is_pointer(int** const volatile));
+SA(__is_pointer(int* const* const volatile));
+SA(__is_pointer(int* volatile* const volatile));
+SA(__is_pointer(int* const volatile* const volatile));
+
+SA(!__is_pointer(int&));
+SA(!__is_pointer(const int&));
+SA(!__is_pointer(volatile int&));
+SA(!__is_pointer(const volatile int&));
+
+SA(!__is_pointer(int&&));
+SA(!__is_pointer(const int&&));
+SA(!__is_pointer(volatile int&&));
+SA(!__is_pointer(const volatile int&&));
+
+SA(!__is_pointer(int[3]));
+SA(!__is_pointer(const int[3]));
+SA(!__is_pointer(volatile int[3]));
+SA(!__is_pointer(const volatile int[3]));
+
+SA(!__is_pointer(int(int)));
+SA(__is_pointer(int(*const)(int)));
+SA(__is_pointer(int(*volatile)(int)));
+SA(__is_pointer(int(*const volatile)(int)));
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 31/33] libstdc++: Optimize std::is_pointer compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (29 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
                                             ` (4 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Jonathan Wakely

This patch optimizes the compilation performance of std::is_pointer
by dispatching to the new __is_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/bits/cpp_type_traits.h (__is_pointer): Use __is_pointer
	built-in trait.  Optimize its implementation.
	* include/std/type_traits (is_pointer): Likewise.
	(is_pointer_v): Likewise.

Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/bits/cpp_type_traits.h | 29 ++++++++++++++
 libstdc++-v3/include/std/type_traits        | 44 +++++++++++++++++----
 2 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 4312f32a4e0..c348df97f72 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
   //
   // Pointer types
   //
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp, bool _IsPtr = __is_pointer(_Tp)>
+    struct __is_pointer : __truth_type<_IsPtr>
+    {
+      enum { __value = _IsPtr };
+    };
+#else
   template<typename _Tp>
     struct __is_pointer
     {
@@ -377,6 +384,28 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       typedef __true_type __type;
     };
 
+  template<typename _Tp>
+    struct __is_pointer<_Tp* const>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+
+  template<typename _Tp>
+    struct __is_pointer<_Tp* volatile>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
+  template<typename _Tp>
+    struct __is_pointer<_Tp* const volatile>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+
   //
   // An arithmetic type is an integer type or a floating point type
   //
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 0641ecfdf2b..75a94cb8d7e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
-  template<typename>
-    struct __is_pointer_helper
+  /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+  template<typename _Tp>
+    struct is_pointer
+    : public __bool_constant<__is_pointer(_Tp)>
+    { };
+#else
+  template<typename _Tp>
+    struct is_pointer
     : public false_type { };
 
   template<typename _Tp>
-    struct __is_pointer_helper<_Tp*>
+    struct is_pointer<_Tp*>
     : public true_type { };
 
-  /// is_pointer
   template<typename _Tp>
-    struct is_pointer
-    : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
-    { };
+    struct is_pointer<_Tp* const>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* volatile>
+    : public true_type { };
+
+  template<typename _Tp>
+    struct is_pointer<_Tp* const volatile>
+    : public true_type { };
+#endif
 
   /// is_lvalue_reference
   template<typename>
@@ -3252,8 +3266,22 @@ template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
 #endif
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+  inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
 template <typename _Tp>
-  inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+  inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+  inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_lvalue_reference_v = false;
 template <typename _Tp>
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 32/33] c++: Implement __is_invocable built-in trait
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (30 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:01                           ` [PATCH v25 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
                                             ` (3 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_invocable.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __is_invocable.
	* constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(is_invocable_p): New function.
	* method.h: New file to export build_trait_object in method.cc.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_invocable.
	* g++.dg/ext/is_invocable1.C: New test.
	* g++.dg/ext/is_invocable2.C: New test.
	* g++.dg/ext/is_invocable3.C: New test.
	* g++.dg/ext/is_invocable4.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |   6 +
 gcc/cp/cp-trait.def                      |   1 +
 gcc/cp/method.h                          |  28 ++
 gcc/cp/semantics.cc                      | 135 +++++++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |   3 +
 gcc/testsuite/g++.dg/ext/is_invocable1.C | 337 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable2.C | 139 ++++++++++
 gcc/testsuite/g++.dg/ext/is_invocable3.C |  51 ++++
 gcc/testsuite/g++.dg/ext/is_invocable4.C |  33 +++
 9 files changed, 733 insertions(+)
 create mode 100644 gcc/cp/method.h
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 9fce36e12d1..29bf548d30a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3754,6 +3754,12 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FUNCTION:
       inform (loc, "  %qT is not a function", t1);
       break;
+    case CPTK_IS_INVOCABLE:
+      if (!t2)
+    inform (loc, "  %qT is not invocable", t1);
+      else
+    inform (loc, "  %qT is not invocable by %qE", t1, t2);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 05514a51c21..b8b7608c122 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
+DEFTRAIT_EXPR (IS_INVOCABLE, "__is_invocable", -1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/method.h b/gcc/cp/method.h
new file mode 100644
index 00000000000..1aec8ec5cfd
--- /dev/null
+++ b/gcc/cp/method.h
@@ -0,0 +1,28 @@
+/* Functions exported by method.cc.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_CP_METHOD_H
+#define GCC_CP_METHOD_H 1
+
+#include "tree.h"
+
+/* In method.cc  */
+extern tree build_trait_object (tree type);
+
+#endif  /* GCC_CP_METHOD_H  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 7cccbae5287..cc2e400531a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "predict.h"
 #include "memmodel.h"
+#include "method.h"
+
+#include "print-tree.h"
+#include "tree-pretty-print.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
@@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
   return saw_copy;
 }
 
+/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
+
+static bool
+is_invocable_p (tree fn_type, tree arg_types)
+{
+  /* ARG_TYPES must be a TREE_VEC.  */
+  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
+
+  /* Access check is required to determine if the given is invocable.  */
+  deferring_access_check_sentinel acs (dk_no_deferred);
+
+  /* std::is_invocable is an unevaluated context.  */
+  cp_unevaluated cp_uneval_guard;
+
+  bool is_ptrdatamem;
+  bool is_ptrmemfunc;
+  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
+    {
+      tree deref_fn_type = TREE_TYPE (fn_type);
+      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
+      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
+
+      /* Dereference fn_type if it is a pointer to member.  */
+      if (is_ptrdatamem || is_ptrmemfunc)
+	fn_type = deref_fn_type;
+    }
+  else
+    {
+      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
+      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
+    }
+
+  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
+    /* A pointer to data member with non-one argument is not invocable.  */
+    return false;
+
+  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
+    /* A pointer to member function with no arguments is not invocable.  */
+    return false;
+
+  /* Construct an expression of a pointer to member.  */
+  tree datum;
+  if (is_ptrdatamem || is_ptrmemfunc)
+    {
+      tree datum_type = TREE_VEC_ELT (arg_types, 0);
+
+      /* Dereference datum.  */
+      if (CLASS_TYPE_P (datum_type))
+	{
+	  bool is_refwrap = false;
+
+	  tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
+	  if (decl_in_std_namespace_p (datum_decl))
+	    {
+	      tree name = DECL_NAME (datum_decl);
+	      if (name && (id_equal (name, "reference_wrapper")))
+		{
+		  /* Handle std::reference_wrapper.  */
+		  is_refwrap = true;
+		  datum_type = cp_build_reference_type (datum_type, false);
+		}
+	    }
+
+	  datum = build_trait_object (datum_type);
+
+	  /* If datum_type was not std::reference_wrapper, check if it has
+	     operator*() overload.  If datum_type was std::reference_wrapper,
+	     avoid dereferencing the datum twice.  */
+	  if (!is_refwrap)
+	    if (get_class_binding (datum_type, get_identifier ("operator*")))
+	      /* Handle operator*().  */
+	      datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
+					    RO_UNARY_STAR, NULL_TREE,
+					    tf_none);
+	}
+      else if (POINTER_TYPE_P (datum_type))
+	datum = build_trait_object (TREE_TYPE (datum_type));
+      else
+	datum = build_trait_object (datum_type);
+    }
+
+  /* Build a function expression.  */
+  tree fn;
+  if (is_ptrdatamem)
+    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
+  else if (is_ptrmemfunc)
+    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
+  else
+    fn = build_trait_object (fn_type);
+
+  /* Construct arguments to the function and an expression of a call.  */
+  if (!is_ptrdatamem)
+    {
+      releasing_vec args;
+
+      if (is_ptrmemfunc)
+	{
+	  /* A pointer to member function is internally converted to a pointer
+	     to function that takes a pointer to the dereferenced datum type
+	     as its first argument and original arguments afterward.  If the
+	     function is a const member function, the first argument also
+	     requires a const datum pointer and vice-versa.  */
+
+	  tree datum_type = TREE_TYPE (datum);
+	  if (TYPE_REF_P (datum_type))
+	    datum_type = TREE_TYPE (datum_type);
+
+	  datum = build_trait_object (build_pointer_type (datum_type));
+	  vec_safe_push (args, datum);
+	}
+
+      for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
+	{
+	  tree arg_type = TREE_VEC_ELT (arg_types, i);
+	  tree arg = build_trait_object (arg_type);
+	  vec_safe_push (args, arg);
+	}
+
+      fn = finish_call_expr (fn, &args, false, false, tf_none);
+    }
+
+  if (error_operand_p (fn))
+    return false;
+
+  return true;
+}
+
 /* Return true if DERIVED is pointer interconvertible base of BASE.  */
 
 static bool
@@ -12181,6 +12312,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FUNCTION:
       return type_code1 == FUNCTION_TYPE;
 
+    case CPTK_IS_INVOCABLE:
+      return is_invocable_p (type1, type2);
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12390,6 +12524,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_CONVERTIBLE:
+    case CPTK_IS_INVOCABLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b1430e9bd8b..3a9bda1ee03 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -92,6 +92,9 @@
 #if !__has_builtin (__is_function)
 # error "__has_builtin (__is_function) failed"
 #endif
+#if !__has_builtin (__is_invocable)
+# error "__has_builtin (__is_invocable) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable1.C b/gcc/testsuite/g++.dg/ext/is_invocable1.C
new file mode 100644
index 00000000000..2fd3906b571
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable1.C
@@ -0,0 +1,337 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+using func_type_v0 = void(*)();
+
+SA(   __is_invocable( func_type_v0 ) );
+SA( ! __is_invocable( func_type_v0, int ) );
+
+using func_type_i0 = int(*)();
+
+SA(   __is_invocable( func_type_i0 ) );
+SA( ! __is_invocable( func_type_i0, int ) );
+
+using func_type_l0 = int&(*)();
+
+SA(   __is_invocable( func_type_l0 ) );
+SA( ! __is_invocable( func_type_l0(int) ) );
+
+using func_type_ii = int(*)(int);
+
+SA( ! __is_invocable( func_type_ii ) );
+SA(   __is_invocable( func_type_ii, int ) );
+
+using func_type_il = int(*)(int&);
+
+SA( ! __is_invocable( func_type_il ) );
+SA( ! __is_invocable( func_type_il, int ) );
+SA(   __is_invocable( func_type_il, int& ) );
+
+using func_type_ir = int(*)(int&&);
+
+SA( ! __is_invocable( func_type_ir ) );
+SA( ! __is_invocable( func_type_ir, int& ) );
+SA(   __is_invocable( func_type_ir, int ) );
+SA(   __is_invocable( func_type_ir, int&& ) );
+
+struct A { };
+
+using mem_type_i = int A::*;
+
+SA( ! __is_invocable( mem_type_i ) );
+SA( ! __is_invocable( mem_type_i, int ) );
+SA( ! __is_invocable( mem_type_i, int* ) );
+SA( ! __is_invocable( mem_type_i, int& ) );
+SA( ! __is_invocable( mem_type_i, int&& ) );
+SA(   __is_invocable( mem_type_i, A ) );
+SA(   __is_invocable( mem_type_i, A* ) );
+SA(   __is_invocable( mem_type_i, A& ) );
+SA(   __is_invocable( mem_type_i, A&& ) );
+SA(   __is_invocable( mem_type_i, const A& ) );
+SA( ! __is_invocable( mem_type_i, A&, int ) );
+
+using memfun_type_i = int (A::*)();
+
+SA( ! __is_invocable( memfun_type_i ) );
+SA( ! __is_invocable( memfun_type_i, int ) );
+SA( ! __is_invocable( memfun_type_i, int* ) );
+SA( ! __is_invocable( memfun_type_i, int& ) );
+SA( ! __is_invocable( memfun_type_i, int&& ) );
+SA(   __is_invocable( memfun_type_i, A ) );
+SA(   __is_invocable( memfun_type_i, A* ) );
+SA(   __is_invocable( memfun_type_i, A& ) );
+SA(   __is_invocable( memfun_type_i, A&& ) );
+SA( ! __is_invocable( memfun_type_i, const A& ) );
+SA( ! __is_invocable( memfun_type_i, A&, int ) );
+
+using memfun_type_ic = int (A::*)() const;
+
+SA( ! __is_invocable( memfun_type_ic ) );
+SA( ! __is_invocable( memfun_type_ic, int ) );
+SA( ! __is_invocable( memfun_type_ic, int& ) );
+SA(   __is_invocable( memfun_type_ic, A& ) );
+SA(   __is_invocable( memfun_type_ic, A* ) );
+SA( ! __is_invocable( memfun_type_ic, A&, int ) );
+SA( ! __is_invocable( memfun_type_ic, A*, int& ) );
+SA(   __is_invocable( memfun_type_ic, const A& ) );
+SA(   __is_invocable( memfun_type_ic, const A* ) );
+SA( ! __is_invocable( memfun_type_ic, const A&, int& ) );
+SA( ! __is_invocable( memfun_type_ic, const A*, int ) );
+
+using memfun_type_iic = int& (A::*)(int&) const;
+
+SA( ! __is_invocable( memfun_type_iic ) );
+SA( ! __is_invocable( memfun_type_iic, int ) );
+SA( ! __is_invocable( memfun_type_iic, int& ) );
+SA( ! __is_invocable( memfun_type_iic, A&, int ) );
+SA(   __is_invocable( memfun_type_iic, A&, int& ) );
+SA( ! __is_invocable( memfun_type_iic, A*, int ) );
+SA(   __is_invocable( memfun_type_iic, A*, int& ) );
+SA( ! __is_invocable( memfun_type_iic, const A&, int ) );
+SA( ! __is_invocable( memfun_type_iic, const A&, int&, int ) );
+SA(   __is_invocable( memfun_type_iic, const A&, int& ) );
+SA(   __is_invocable( memfun_type_iic, const A*, int& ) );
+
+struct B {
+  int& operator()();
+  long& operator()() const;
+  bool& operator()(int);
+private:
+  void operator()(int, int);
+};
+using CB = const B;
+
+SA(   __is_invocable( B ) );
+SA(   __is_invocable( B& ) );
+SA(   __is_invocable( B&& ) );
+SA( ! __is_invocable( B* ) );
+SA(   __is_invocable( CB ) );
+SA(   __is_invocable( CB& ) );
+SA( ! __is_invocable( CB* ) );
+
+SA(   __is_invocable( B, int ) );
+SA(   __is_invocable( B&, int ) );
+SA(   __is_invocable( B&&, int ) );
+SA( ! __is_invocable( B*, int ) );
+SA( ! __is_invocable( CB, int ) );
+SA( ! __is_invocable( CB&, int ) );
+SA( ! __is_invocable( CB*, int ) );
+
+SA( ! __is_invocable( B, int, int ) );
+SA( ! __is_invocable( B&, int, int ) );
+SA( ! __is_invocable( B&&, int, int ) );
+SA( ! __is_invocable( B*, int, int ) );
+SA( ! __is_invocable( CB, int, int ) );
+SA( ! __is_invocable( CB&, int, int ) );
+SA( ! __is_invocable( CB*, int, int ) );
+
+struct C : B { int& operator()() = delete; };
+using CC = const C;
+
+SA( ! __is_invocable( C ) );
+SA( ! __is_invocable( C& ) );
+SA( ! __is_invocable( C&& ) );
+SA( ! __is_invocable( C* ) );
+SA( ! __is_invocable( CC ) );
+SA( ! __is_invocable( CC& ) );
+SA( ! __is_invocable( CC* ) );
+
+struct D { B operator*(); };
+using CD = const D;
+
+SA( ! __is_invocable( D ) );
+
+struct E { void v(); };
+using CE = const E;
+
+SA( ! __is_invocable( E ) );
+SA( ! __is_invocable( void (E::*)() ) );
+SA(   __is_invocable( void (E::*)(), E ) );
+SA(   __is_invocable( void (E::*)(), E* ) );
+SA( ! __is_invocable( void (E::*)(), CE ) );
+
+struct F : E {};
+using CF = const F;
+
+SA( ! __is_invocable( F ) );
+SA(   __is_invocable( void (E::*)(), F ) );
+SA(   __is_invocable( void (E::*)(), F* ) );
+SA( ! __is_invocable( void (E::*)(), CF ) );
+
+struct G { E operator*(); };
+using CG = const G;
+
+SA( ! __is_invocable( G ) );
+SA(   __is_invocable( void (E::*)(), G ) );
+SA( ! __is_invocable( void (E::*)(), G* ) );
+SA( ! __is_invocable( void (E::*)(), CG ) );
+
+struct H { E& operator*(); };
+using CH = const H;
+
+SA( ! __is_invocable( H ) );
+SA(   __is_invocable( void (E::*)(), H ) );
+SA( ! __is_invocable( void (E::*)(), H* ) );
+SA( ! __is_invocable( void (E::*)(), CH ) );
+
+struct I { E&& operator*(); };
+using CI = const I;
+
+SA( ! __is_invocable( I ) );
+SA(   __is_invocable( void (E::*)(), I ) );
+SA( ! __is_invocable( void (E::*)(), I* ) );
+SA( ! __is_invocable( void (E::*)(), CI ) );
+
+struct K { E* operator*(); };
+using CK = const K;
+
+SA( ! __is_invocable( K ) );
+SA( ! __is_invocable( void (E::*)(), K ) );
+SA( ! __is_invocable( void (E::*)(), K* ) );
+SA( ! __is_invocable( void (E::*)(), CK ) );
+
+struct L { CE operator*(); };
+using CL = const L;
+
+SA( ! __is_invocable( L ) );
+SA( ! __is_invocable( void (E::*)(), L ) );
+SA( ! __is_invocable( void (E::*)(), L* ) );
+SA( ! __is_invocable( void (E::*)(), CL ) );
+
+struct M {
+  int i;
+private:
+  long l;
+};
+using CM = const M;
+
+SA( ! __is_invocable( M ) );
+SA( ! __is_invocable( M& ) );
+SA( ! __is_invocable( M&& ) );
+SA( ! __is_invocable( M* ) );
+SA( ! __is_invocable( CM ) );
+SA( ! __is_invocable( CM& ) );
+SA( ! __is_invocable( CM* ) );
+
+SA( ! __is_invocable( int M::* ) );
+SA(   __is_invocable( int M::*, M ) );
+SA(   __is_invocable( int M::*, M& ) );
+SA(   __is_invocable( int M::*, M&& ) );
+SA(   __is_invocable( int M::*, M* ) );
+SA(   __is_invocable( int M::*, CM ) );
+SA(   __is_invocable( int M::*, CM& ) );
+SA(   __is_invocable( int M::*, CM* ) );
+SA( ! __is_invocable( int M::*, int ) );
+
+SA( ! __is_invocable( int CM::* ) );
+SA(   __is_invocable( int CM::*, M ) );
+SA(   __is_invocable( int CM::*, M& ) );
+SA(   __is_invocable( int CM::*, M&& ) );
+SA(   __is_invocable( int CM::*, M* ) );
+SA(   __is_invocable( int CM::*, CM ) );
+SA(   __is_invocable( int CM::*, CM& ) );
+SA(   __is_invocable( int CM::*, CM* ) );
+SA( ! __is_invocable( int CM::*, int ) );
+
+SA( ! __is_invocable( long M::* ) );
+SA(   __is_invocable( long M::*, M ) );
+SA(   __is_invocable( long M::*, M& ) );
+SA(   __is_invocable( long M::*, M&& ) );
+SA(   __is_invocable( long M::*, M* ) );
+SA(   __is_invocable( long M::*, CM ) );
+SA(   __is_invocable( long M::*, CM& ) );
+SA(   __is_invocable( long M::*, CM* ) );
+SA( ! __is_invocable( long M::*, long ) );
+
+SA( ! __is_invocable( long CM::* ) );
+SA(   __is_invocable( long CM::*, M ) );
+SA(   __is_invocable( long CM::*, M& ) );
+SA(   __is_invocable( long CM::*, M&& ) );
+SA(   __is_invocable( long CM::*, M* ) );
+SA(   __is_invocable( long CM::*, CM ) );
+SA(   __is_invocable( long CM::*, CM& ) );
+SA(   __is_invocable( long CM::*, CM* ) );
+SA( ! __is_invocable( long CM::*, long ) );
+
+SA( ! __is_invocable( short M::* ) );
+SA(   __is_invocable( short M::*, M ) );
+SA(   __is_invocable( short M::*, M& ) );
+SA(   __is_invocable( short M::*, M&& ) );
+SA(   __is_invocable( short M::*, M* ) );
+SA(   __is_invocable( short M::*, CM ) );
+SA(   __is_invocable( short M::*, CM& ) );
+SA(   __is_invocable( short M::*, CM* ) );
+SA( ! __is_invocable( short M::*, short ) );
+
+SA( ! __is_invocable( short CM::* ) );
+SA(   __is_invocable( short CM::*, M ) );
+SA(   __is_invocable( short CM::*, M& ) );
+SA(   __is_invocable( short CM::*, M&& ) );
+SA(   __is_invocable( short CM::*, M* ) );
+SA(   __is_invocable( short CM::*, CM ) );
+SA(   __is_invocable( short CM::*, CM& ) );
+SA(   __is_invocable( short CM::*, CM* ) );
+SA( ! __is_invocable( short CM::*, short ) );
+
+struct N { M operator*(); };
+SA(   __is_invocable( int M::*, N ) );
+SA( ! __is_invocable( int M::*, N* ) );
+
+struct O { M& operator*(); };
+SA(   __is_invocable( int M::*, O ) );
+SA( ! __is_invocable( int M::*, O* ) );
+
+struct P { M&& operator*(); };
+SA(   __is_invocable( int M::*, P ) );
+SA( ! __is_invocable( int M::*, P* ) );
+
+struct Q { M* operator*(); };
+SA( ! __is_invocable( int M::*, Q ) );
+SA( ! __is_invocable( int M::*, Q* ) );
+
+struct R { void operator()(int = 0); };
+
+SA(   __is_invocable( R ) );
+SA(   __is_invocable( R, int ) );
+SA( ! __is_invocable( R, int, int ) );
+
+struct S { void operator()(int, ...); };
+
+SA( ! __is_invocable( S ) );
+SA(   __is_invocable( S, int ) );
+SA(   __is_invocable( S, int, int ) );
+SA(   __is_invocable( S, int, int, int ) );
+
+void fn1() {}
+
+SA(   __is_invocable( decltype(fn1) ) );
+
+void fn2(int arr[10]);
+
+SA(   __is_invocable( decltype(fn2), int[10] ) );
+SA(   __is_invocable( decltype(fn2), int(&)[10] ) );
+SA(   __is_invocable( decltype(fn2), int(&&)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*&)[10] ) );
+SA( ! __is_invocable( decltype(fn2), int(*&&)[10] ) );
+SA(   __is_invocable( decltype(fn2), int[] ) );
+
+auto lambda = []() {};
+
+SA(   __is_invocable( decltype(lambda) ) );
+
+template <typename Func, typename... Args>
+struct can_invoke {
+    static constexpr bool value = __is_invocable( Func, Args... );
+};
+
+SA( can_invoke<decltype(lambda)>::value );
+
+struct T {
+  void func() const {}
+  int data;
+};
+
+SA(   __is_invocable( decltype(&T::func)&, T& ) );
+SA(   __is_invocable( decltype(&T::data)&, T& ) );
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable2.C b/gcc/testsuite/g++.dg/ext/is_invocable2.C
new file mode 100644
index 00000000000..a68aefd3e13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable2.C
@@ -0,0 +1,139 @@
+// { dg-do compile { target c++11 } }
+// __is_invocable should handle std::reference_wrapper correctly.
+
+#include <functional>
+
+#define SA(X) static_assert((X),#X)
+
+using std::reference_wrapper;
+
+using func_type_v0 = void(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_v0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_v0>, int ) );
+
+using func_type_i0 = int(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_i0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_i0>, int ) );
+
+using func_type_l0 = int&(*)();
+
+SA(   __is_invocable( reference_wrapper<func_type_l0> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_l0(int)> ) );
+
+using func_type_ii = int(*)(int);
+
+SA( ! __is_invocable( reference_wrapper<func_type_ii> ) );
+SA(   __is_invocable( reference_wrapper<func_type_ii>, int ) );
+
+using func_type_il = int(*)(int&);
+
+SA( ! __is_invocable( reference_wrapper<func_type_il> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_il>, int ) );
+SA(   __is_invocable( reference_wrapper<func_type_il>, int& ) );
+
+using func_type_ir = int(*)(int&&);
+
+SA( ! __is_invocable( reference_wrapper<func_type_ir> ) );
+SA( ! __is_invocable( reference_wrapper<func_type_ir>, int& ) );
+SA(   __is_invocable( reference_wrapper<func_type_ir>, int ) );
+SA(   __is_invocable( reference_wrapper<func_type_ir>, int&& ) );
+
+struct A { };
+
+using mem_type_i = int A::*;
+
+SA( ! __is_invocable( reference_wrapper<mem_type_i> ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int* ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int& ) );
+SA( ! __is_invocable( reference_wrapper<mem_type_i>, int&& ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A* ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A& ) );
+SA(   __is_invocable( reference_wrapper<mem_type_i>, A&& ) );
+
+using memfun_type_i = int (A::*)();
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_i> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, int&& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A* ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_i>, A&& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, const A& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_i>, A&, int ) );
+
+using memfun_type_ic = int (A::*)() const;
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, A* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A&, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, A*, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_ic>, const A* ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A&, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_ic>, const A*, int ) );
+
+using memfun_type_iic = int& (A::*)(int&) const;
+
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic> ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A&, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A&, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, A*, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, A*, int& ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int ) );
+SA( ! __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int&, int ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A&, int& ) );
+SA(   __is_invocable( reference_wrapper<memfun_type_iic>, const A*, int& ) );
+
+struct B {
+  int& operator()();
+  long& operator()() const;
+  bool& operator()(int);
+private:
+  void operator()(int, int);
+};
+using CB = const B;
+
+SA(   __is_invocable( reference_wrapper<B> ) );
+SA(   __is_invocable( reference_wrapper<B>& ) );
+SA(   __is_invocable( reference_wrapper<B>&& ) );
+SA(   __is_invocable( reference_wrapper<CB> ) );
+SA(   __is_invocable( reference_wrapper<CB>& ) );
+SA(   __is_invocable( reference_wrapper<B>, int ) );
+SA( ! __is_invocable( reference_wrapper<B>&, int, int ) );
+
+struct C : B { int& operator()() = delete; };
+using CC = const C;
+
+SA( ! __is_invocable( reference_wrapper<C> ) );
+SA( ! __is_invocable( reference_wrapper<C>& ) );
+SA( ! __is_invocable( reference_wrapper<C>&& ) );
+SA( ! __is_invocable( reference_wrapper<CC> ) );
+SA( ! __is_invocable( reference_wrapper<CC>& ) );
+
+struct D { B operator*(); };
+using CD = const D;
+
+SA( ! __is_invocable( reference_wrapper<D> ) );
+SA( ! __is_invocable( reference_wrapper<D>& ) );
+SA( ! __is_invocable( reference_wrapper<D>&& ) );
+SA( ! __is_invocable( reference_wrapper<D>* ) );
+SA( ! __is_invocable( reference_wrapper<D*> ) );
+SA( ! __is_invocable( reference_wrapper<D*>* ) );
+
+std::function<void()> fn = []() {};
+auto refwrap = std::ref(fn);
+
+SA(   __is_invocable( decltype(fn) ) );
+SA(   __is_invocable( decltype(refwrap) ) );
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable3.C b/gcc/testsuite/g++.dg/ext/is_invocable3.C
new file mode 100644
index 00000000000..e2b0c5ef406
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable3.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+// __is_invocable should handle incomplete class correctly.
+
+#define SA(X) static_assert((X),#X)
+
+struct Incomplete;
+
+SA( ! __is_invocable( Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( int, Incomplete, int ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int, Incomplete ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( Incomplete, Incomplete() ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, Incomplete(int), int ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( Incomplete, Incomplete(int, int), int, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( Incomplete, Incomplete(), int, int ) ); // { dg-error "incomplete type" }
+
+SA( ! __is_invocable( int(Incomplete), Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int(int, Incomplete), int, Incomplete ) ); // { dg-error "incomplete type" }
+SA( ! __is_invocable( int(int, Incomplete), Incomplete, int ) ); // { dg-error "incomplete type" }
+
+SA(   __is_invocable( int(Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(Incomplete&&), Incomplete&& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, Incomplete&&), int, Incomplete&& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&&), const Incomplete&& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&&), int, const Incomplete&& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&), const Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&), int, const Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int(const Incomplete&), Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( int(int, const Incomplete&), int, Incomplete& ) ); // { dg-bogus "incomplete type" }
+
+SA(   __is_invocable( int Incomplete::*, const Incomplete& ) ); // { dg-bogus "incomplete type" }
+SA( ! __is_invocable( void (Incomplete::*)(long&), const Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
+SA(   __is_invocable( void (Incomplete::*)(long&) const, Incomplete*, long& ) ); // { dg-bogus "incomplete type" }
+
+template <typename T>
+struct Holder { T t; };
+
+SA(   __is_invocable( int(Holder<Incomplete>&), Holder<Incomplete>& ) ); // { dg-bogus "incomplete type" }
+
+// Define Incomplete, which is now not incomplete.
+struct Incomplete { void operator()(); };
+
+SA( __is_invocable( Incomplete ) ); // { dg-bogus "incomplete type" }
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable4.C b/gcc/testsuite/g++.dg/ext/is_invocable4.C
new file mode 100644
index 00000000000..d1efccf08f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable4.C
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++11 } }
+// Failed access check should be a substitution failure, not an error.
+
+#define SA(X) static_assert((X),#X)
+
+template<bool B>
+struct bool_constant { static constexpr bool value = B; };
+
+template<typename _Fn, typename... _ArgTypes>
+struct is_invocable
+: public bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+{ };
+
+#if __cpp_variable_templates
+template<typename _Fn, typename... _ArgTypes>
+constexpr bool is_invocable_v = __is_invocable(_Fn, _ArgTypes...);
+#endif
+
+class Private
+{
+  void operator()() const
+  {
+    SA( ! is_invocable<Private>::value );
+#if __cpp_variable_templates
+    SA( ! is_invocable_v<Private> );
+#endif
+  }
+};
+
+SA( ! is_invocable<Private>::value );
+#if __cpp_variable_templates
+SA( ! is_invocable_v<Private> );
+#endif
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v25 33/33] libstdc++: Optimize std::is_invocable compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (31 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
@ 2023-10-24  2:01                           ` Ken Matsui
  2023-10-24  2:07                           ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (2 subsequent siblings)
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:01 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_invocable
by dispatching to the new __is_invocable built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_invocable): Use __is_invocable
	built-in trait.
	* testsuite/20_util/is_invocable/incomplete_args_neg.cc: Handle
	the new error from __is_invocable.
	* testsuite/20_util/is_invocable/incomplete_neg.cc: Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits                        | 6 ++++++
 .../testsuite/20_util/is_invocable/incomplete_args_neg.cc   | 1 +
 .../testsuite/20_util/is_invocable/incomplete_neg.cc        | 1 +
 3 files changed, 8 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 75a94cb8d7e..91851b78c7e 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3167,9 +3167,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
 
   /// std::is_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+  template<typename _Fn, typename... _ArgTypes>
+    struct is_invocable
+    : public __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+#else
   template<typename _Fn, typename... _ArgTypes>
     struct is_invocable
     : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
+#endif
     {
       static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}),
 	"_Fn must be a complete class or an unbounded array");
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
index 34d1d9431d1..3f9e5274f3c 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_args_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-prune-output "invalid use of incomplete type" }
 
 #include <type_traits>
 
diff --git a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
index e1e54d25ee5..92af48c48b6 100644
--- a/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/is_invocable/incomplete_neg.cc
@@ -18,6 +18,7 @@
 // <http://www.gnu.org/licenses/>.
 
 // { dg-error "must be a complete class" "" { target *-*-* } 0 }
+// { dg-prune-output "invalid use of incomplete type" }
 
 #include <type_traits>
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v25 00/33] Optimize type traits compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (32 preceding siblings ...)
  2023-10-24  2:01                           ` [PATCH v25 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
@ 2023-10-24  2:07                           ` Ken Matsui
  2023-12-07  5:11                           ` [PATCH v26 00/23] " Ken Matsui
  2023-12-07  5:32                           ` Ken Matsui
  35 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-10-24  2:07 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

I accidentally sent is_invocable patches as well, but those have no changes.

On Mon, Oct 23, 2023 at 7:04 PM Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>
> This patch series optimizes type traits compilation performance by
> implementing built-in type traits and using them in libstdc++.
>
> Changes in v25:
>
>         * Optimized the __is_pointer implementation in cpp_type_traits.h.
>         * Fix compilation error in cpp_type_traits.h with Clang 16.
>         * Wrapped commit messages at 75 columns.
>         * Used & instead of && for the new IDENTIFIER_TRAIT_P macro.
>         * Made cp_lexer_peek_trait not to take cp_token.
>         * Fixed indentation error in cp_lexer_peek_trait.
>
> Changes in v24:
>
>         * Fixed the way to handle an incomplete type error from __is_invocable
>         in the test cases so that we can correctly test both the use of
>         built-in and vice-versa.
>
> Changes in v23:
>
>         * Improved the comment in cp-tree.h.
>         * Moved the definition of cp_traits to lex.cc from parser.cc.
>         * Implemented __is_invocable built-in trait.
>
> Changes in v22:
>
>         * Included a missing patch in v21.
>
> Changes in v21:
>
>         * Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
>         cpp_type_traits.h.
>         * Added const char* name to struct cp_trait, and loop over cp_traits
>         in init_cp_traits to get the name.
>         * Isolated patches for integral-related built-in traits from
>         this patch series since they are not ready for review yet.
>         * Implemented __is_object built-in trait.
>
> Changes in v20:
>
>         * Used identifier node instead of gperf to look up built-in
>         traits.
>
> Changes in v19:
>
>         * Fixed a typo.
>         * Rebased on top of trunk.
>         * Improved clarity of the commit message.
>
> Changes in v18:
>
>         * Removed all RID values for built-in traits and used cik_trait
>         instead.
>         * Improved to handle the use of non-function-like built-in trait
>         identifiers.
>         * Reverted all changes to conflicted identifiers with new built-ins
>         in the existing code base.
>
> Changes in v17:
>
>         * Rebased on top of trunk.
>         * Improved clarity of the commit message.
>         * Simplified Make-lang.in.
>         * Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.
>
> Changes in v16:
>
>         * Rebased on top of trunk.
>         * Improved clarity of the commit message.
>         * Simplified Make-lang.in and gperf struct.
>         * Supply -k option to gperf to support older versions than 2.8.
>
> Changes in v15:
>
>         * Rebased on top of trunk.
>         * Use gperf to look up traits instead of enum rid.
>
> Changes in v14:
>
>         * Added padding calculation to the commit message.
>
> Changes in v13:
>
>         * Fixed ambiguous commit message and comment.
>
> Changes in v12:
>
>         * Evaluated all paddings affected by the enum rid change.
>
> Changes in v11:
>
>         * Merged all patches into one patch series.
>         * Rebased on top of trunk.
>         * Unified commit message style.
>         * Used _GLIBCXX_USE_BUILTIN_TRAIT.
>
> Ken Matsui (33):
>   c++: Sort built-in traits alphabetically
>   c-family, c++: Look up built-in traits via identifier node
>   c++: Accept the use of built-in trait identifiers
>   c++: Implement __is_const built-in trait
>   libstdc++: Optimize std::is_const compilation performance
>   c++: Implement __is_volatile built-in trait
>   libstdc++: Optimize std::is_volatile compilation performance
>   c++: Implement __is_array built-in trait
>   libstdc++: Optimize std::is_array compilation performance
>   c++: Implement __is_unbounded_array built-in trait
>   libstdc++: Optimize std::is_unbounded_array compilation performance
>   c++: Implement __is_bounded_array built-in trait
>   libstdc++: Optimize std::is_bounded_array compilation performance
>   c++: Implement __is_scoped_enum built-in trait
>   libstdc++: Optimize std::is_scoped_enum compilation performance
>   c++: Implement __is_member_pointer built-in trait
>   libstdc++: Optimize std::is_member_pointer compilation performance
>   c++: Implement __is_member_function_pointer built-in trait
>   libstdc++: Optimize std::is_member_function_pointer compilation
>     performance
>   c++: Implement __is_member_object_pointer built-in trait
>   libstdc++: Optimize std::is_member_object_pointer compilation
>     performance
>   c++: Implement __is_reference built-in trait
>   libstdc++: Optimize std::is_reference compilation performance
>   c++: Implement __is_function built-in trait
>   libstdc++: Optimize std::is_function compilation performance
>   c++: Implement __is_object built-in trait
>   libstdc++: Optimize std::is_object compilation performance
>   c++: Implement __remove_pointer built-in trait
>   libstdc++: Optimize std::remove_pointer compilation performance
>   c++: Implement __is_pointer built-in trait
>   libstdc++: Optimize std::is_pointer compilation performance
>   c++: Implement __is_invocable built-in trait
>   libstdc++: Optimize std::is_invocable compilation performance
>
>  gcc/c-family/c-common.cc                      |   7 -
>  gcc/c-family/c-common.h                       |   5 -
>  gcc/cp/constraint.cc                          | 109 ++++--
>  gcc/cp/cp-objcp-common.cc                     |   8 +-
>  gcc/cp/cp-trait.def                           |  25 +-
>  gcc/cp/cp-tree.h                              |  32 +-
>  gcc/cp/lex.cc                                 |  34 ++
>  gcc/cp/method.h                               |  28 ++
>  gcc/cp/parser.cc                              | 120 ++++---
>  gcc/cp/semantics.cc                           | 284 ++++++++++++---
>  gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 113 ++++--
>  gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++
>  gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 ++
>  gcc/testsuite/g++.dg/ext/is_const.C           |  19 +
>  gcc/testsuite/g++.dg/ext/is_function.C        |  58 +++
>  gcc/testsuite/g++.dg/ext/is_invocable1.C      | 337 ++++++++++++++++++
>  gcc/testsuite/g++.dg/ext/is_invocable2.C      | 139 ++++++++
>  gcc/testsuite/g++.dg/ext/is_invocable3.C      |  51 +++
>  gcc/testsuite/g++.dg/ext/is_invocable4.C      |  33 ++
>  .../g++.dg/ext/is_member_function_pointer.C   |  31 ++
>  .../g++.dg/ext/is_member_object_pointer.C     |  30 ++
>  gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++
>  gcc/testsuite/g++.dg/ext/is_object.C          |  29 ++
>  gcc/testsuite/g++.dg/ext/is_pointer.C         |  51 +++
>  gcc/testsuite/g++.dg/ext/is_reference.C       |  34 ++
>  gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 ++++
>  gcc/testsuite/g++.dg/ext/is_unbounded_array.C |  37 ++
>  gcc/testsuite/g++.dg/ext/is_volatile.C        |  19 +
>  gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++
>  libstdc++-v3/include/bits/cpp_type_traits.h   |  29 ++
>  libstdc++-v3/include/std/type_traits          | 219 +++++++++++-
>  .../is_invocable/incomplete_args_neg.cc       |   1 +
>  .../20_util/is_invocable/incomplete_neg.cc    |   1 +
>  33 files changed, 1901 insertions(+), 196 deletions(-)
>  create mode 100644 gcc/cp/method.h
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_const.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable1.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable2.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable3.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_invocable4.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_pointer.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_unbounded_array.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/is_volatile.C
>  create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C
>
> --
> 2.42.0
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance
  2023-10-24  2:01                           ` [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-10-24 11:01                             ` Jonathan Wakely
  2023-12-07  3:20                               ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Jonathan Wakely @ 2023-10-24 11:01 UTC (permalink / raw)
  To: Ken Matsui; +Cc: gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 1811 bytes --]

On Tue, 24 Oct 2023 at 03:16, Ken Matsui <kmatsui@gcc.gnu.org> wrote:

> This patch optimizes the compilation performance of std::is_function
> by dispatching to the new __is_function built-in trait.
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/type_traits (is_function): Use __is_function
>         built-in trait.
>         (is_function_v): Likewise. Optimize its implementation.
>         (is_const_v): Move on top of is_function_v as is_function_v now
>         depends on is_const_v.
>

I think I'd prefer to keep is_const_v where it is now, adjacent to
is_volatile_v, and move is_function_v after those.

i.e. like this (but with the additional changes to use the new built-in):

--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3198,8 +3198,8 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
-template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+// is_function_v is defined below, after is_const_v.
+
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
@@ -3226,6 +3226,8 @@ template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
   inline constexpr bool is_volatile_v<volatile _Tp> = true;
+template <typename _Tp>
+  inline constexpr bool is_function_v = is_function<_Tp>::value;

 template <typename _Tp>
   inline constexpr bool is_trivial_v = __is_trivial(_Tp);

The variable templates are currently defined in the order shown in the
standard, in te [meta.type.synop] synopsis, and in the [meta.unary.cat]
table. So let's move _is_function_v later and add a comment saying why it's
not in the expected place.

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance
  2023-10-24 11:01                             ` Jonathan Wakely
@ 2023-12-07  3:20                               ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  3:20 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Ken Matsui, gcc-patches, libstdc++

On Tue, Oct 24, 2023 at 4:02 AM Jonathan Wakely <jwakely@redhat.com> wrote:
>
>
>
> On Tue, 24 Oct 2023 at 03:16, Ken Matsui <kmatsui@gcc.gnu.org> wrote:
>>
>> This patch optimizes the compilation performance of std::is_function
>> by dispatching to the new __is_function built-in trait.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * include/std/type_traits (is_function): Use __is_function
>>         built-in trait.
>>         (is_function_v): Likewise. Optimize its implementation.
>>         (is_const_v): Move on top of is_function_v as is_function_v now
>>         depends on is_const_v.
>
>
> I think I'd prefer to keep is_const_v where it is now, adjacent to is_volatile_v, and move is_function_v after those.
>
> i.e. like this (but with the additional changes to use the new built-in):
>
> --- a/libstdc++-v3/include/std/type_traits
> +++ b/libstdc++-v3/include/std/type_traits
> @@ -3198,8 +3198,8 @@ template <typename _Tp>
>    inline constexpr bool is_union_v = __is_union(_Tp);
>  template <typename _Tp>
>    inline constexpr bool is_class_v = __is_class(_Tp);
> -template <typename _Tp>
> -  inline constexpr bool is_function_v = is_function<_Tp>::value;
> +// is_function_v is defined below, after is_const_v.
> +
>  template <typename _Tp>
>    inline constexpr bool is_reference_v = false;
>  template <typename _Tp>
> @@ -3226,6 +3226,8 @@ template <typename _Tp>
>    inline constexpr bool is_volatile_v = false;
>  template <typename _Tp>
>    inline constexpr bool is_volatile_v<volatile _Tp> = true;
> +template <typename _Tp>
> +  inline constexpr bool is_function_v = is_function<_Tp>::value;
>
>  template <typename _Tp>
>    inline constexpr bool is_trivial_v = __is_trivial(_Tp);
>
> The variable templates are currently defined in the order shown in the standard, in te [meta.type.synop] synopsis, and in the [meta.unary.cat] table. So let's move _is_function_v later and add a comment saying why it's not in the expected place.
>
>

Sorry for missing this.  Thank you for your review!  That totally
makes sense, and I will update my patches accordingly.

^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 00/23] Optimize type traits compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (33 preceding siblings ...)
  2023-10-24  2:07                           ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
@ 2023-12-07  5:11                           ` Ken Matsui
  2023-12-10 18:19                             ` Jason Merrill
  2023-12-20  3:22                             ` Sandra Loosemore
  2023-12-07  5:32                           ` Ken Matsui
  35 siblings, 2 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits compilation performance by
implementing built-in type traits and using them in libstdc++.

Changes in v26:

	* Rebased on top of trunk.
	* Moved is_function_v under is_const_v.
	* Isolated patches for is_const, is_volatile, is_pointer, and
	is_unbounded_array, which contain performance regression, from
	this patch series since they are not ready for review yet.

Changes in v25:

	* Optimized the __is_pointer implementation in cpp_type_traits.h.
	* Fix compilation error in cpp_type_traits.h with Clang 16.
	* Wrapped commit messages at 75 columns.
	* Used & instead of && for the new IDENTIFIER_TRAIT_P macro.
	* Made cp_lexer_peek_trait not to take cp_token.
	* Fixed indentation error in cp_lexer_peek_trait.

Changes in v24:

	* Fixed the way to handle an incomplete type error from __is_invocable
	in the test cases so that we can correctly test both the use of
	built-in and vice-versa.

Changes in v23:

	* Improved the comment in cp-tree.h.
	* Moved the definition of cp_traits to lex.cc from parser.cc.
	* Implemented __is_invocable built-in trait.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (23):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance

 gcc/c-family/c-common.cc                      |   7 -
 gcc/c-family/c-common.h                       |   5 -
 gcc/cp/constraint.cc                          |  95 +++++++-----
 gcc/cp/cp-objcp-common.cc                     |   8 +-
 gcc/cp/cp-trait.def                           |  20 ++-
 gcc/cp/cp-tree.h                              |  32 +++--
 gcc/cp/lex.cc                                 |  34 +++++
 gcc/cp/parser.cc                              | 120 ++++++++++------
 gcc/cp/semantics.cc                           | 135 ++++++++++++------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 100 ++++++++-----
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++++
 gcc/testsuite/g++.dg/ext/is_object.C          |  29 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++++++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++++++
 libstdc++-v3/include/std/type_traits          | 135 +++++++++++++++++-
 21 files changed, 898 insertions(+), 189 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 00/23] Optimize type traits compilation performance
  2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
                                             ` (34 preceding siblings ...)
  2023-12-07  5:11                           ` [PATCH v26 00/23] " Ken Matsui
@ 2023-12-07  5:32                           ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 01/23] c++: Sort built-in traits alphabetically Ken Matsui
                                               ` (22 more replies)
  35 siblings, 23 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch series optimizes type traits compilation performance by
implementing built-in type traits and using them in libstdc++.

Changes in v26:

	* Rebased on top of trunk.
	* Moved is_function_v under is_const_v.
	* Isolated is_const, is_volatile, is_pointer, and
	is_unbounded_array patches, which contain performance regression,
	from this patch series.

Changes in v25:

	* Optimized the __is_pointer implementation in cpp_type_traits.h.
	* Fix compilation error in cpp_type_traits.h with Clang 16.
	* Wrapped commit messages at 75 columns.
	* Used & instead of && for the new IDENTIFIER_TRAIT_P macro.
	* Made cp_lexer_peek_trait not to take cp_token.
	* Fixed indentation error in cp_lexer_peek_trait.

Changes in v24:

	* Fixed the way to handle an incomplete type error from __is_invocable
	in the test cases so that we can correctly test both the use of
	built-in and vice-versa.

Changes in v23:

	* Improved the comment in cp-tree.h.
	* Moved the definition of cp_traits to lex.cc from parser.cc.
	* Implemented __is_invocable built-in trait.

Changes in v22:

	* Included a missing patch in v21.

Changes in v21:

	* Used _GLIBCXX_USE_BUILTIN_TRAIT instead of __has_builtin in
	cpp_type_traits.h.
	* Added const char* name to struct cp_trait, and loop over cp_traits
	in init_cp_traits to get the name.
	* Isolated patches for integral-related built-in traits from
	this patch series since they are not ready for review yet.
	* Implemented __is_object built-in trait.

Changes in v20:

	* Used identifier node instead of gperf to look up built-in
	traits.

Changes in v19:

	* Fixed a typo.
	* Rebased on top of trunk.
	* Improved clarity of the commit message.

Changes in v18:

	* Removed all RID values for built-in traits and used cik_trait
	instead.
	* Improved to handle the use of non-function-like built-in trait
	identifiers.
	* Reverted all changes to conflicted identifiers with new built-ins
	in the existing code base.

Changes in v17:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in.
	* Made ridpointers for RID_TRAIT_EXPR and RID_TRAIT_TYPE empty.

Changes in v16:

	* Rebased on top of trunk.
	* Improved clarity of the commit message.
	* Simplified Make-lang.in and gperf struct.
	* Supply -k option to gperf to support older versions than 2.8.

Changes in v15:

	* Rebased on top of trunk.
	* Use gperf to look up traits instead of enum rid.

Changes in v14:

	* Added padding calculation to the commit message.

Changes in v13:

	* Fixed ambiguous commit message and comment.

Changes in v12:

	* Evaluated all paddings affected by the enum rid change.

Changes in v11:

	* Merged all patches into one patch series.
	* Rebased on top of trunk.
	* Unified commit message style.
	* Used _GLIBCXX_USE_BUILTIN_TRAIT.

Ken Matsui (23):
  c++: Sort built-in traits alphabetically
  c-family, c++: Look up built-in traits via identifier node
  c++: Accept the use of built-in trait identifiers
  c++: Implement __is_array built-in trait
  libstdc++: Optimize std::is_array compilation performance
  c++: Implement __is_bounded_array built-in trait
  libstdc++: Optimize std::is_bounded_array compilation performance
  c++: Implement __is_scoped_enum built-in trait
  libstdc++: Optimize std::is_scoped_enum compilation performance
  c++: Implement __is_member_pointer built-in trait
  libstdc++: Optimize std::is_member_pointer compilation performance
  c++: Implement __is_member_function_pointer built-in trait
  libstdc++: Optimize std::is_member_function_pointer compilation
    performance
  c++: Implement __is_member_object_pointer built-in trait
  libstdc++: Optimize std::is_member_object_pointer compilation
    performance
  c++: Implement __is_reference built-in trait
  libstdc++: Optimize std::is_reference compilation performance
  c++: Implement __is_function built-in trait
  libstdc++: Optimize std::is_function compilation performance
  c++: Implement __is_object built-in trait
  libstdc++: Optimize std::is_object compilation performance
  c++: Implement __remove_pointer built-in trait
  libstdc++: Optimize std::remove_pointer compilation performance

 gcc/c-family/c-common.cc                      |   7 -
 gcc/c-family/c-common.h                       |   5 -
 gcc/cp/constraint.cc                          |  95 +++++++-----
 gcc/cp/cp-objcp-common.cc                     |   8 +-
 gcc/cp/cp-trait.def                           |  20 ++-
 gcc/cp/cp-tree.h                              |  32 +++--
 gcc/cp/lex.cc                                 |  34 +++++
 gcc/cp/parser.cc                              | 120 ++++++++++------
 gcc/cp/semantics.cc                           | 135 ++++++++++++------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C      | 100 ++++++++-----
 gcc/testsuite/g++.dg/ext/is_array.C           |  28 ++++
 gcc/testsuite/g++.dg/ext/is_bounded_array.C   |  38 +++++
 gcc/testsuite/g++.dg/ext/is_function.C        |  58 ++++++++
 .../g++.dg/ext/is_member_function_pointer.C   |  31 ++++
 .../g++.dg/ext/is_member_object_pointer.C     |  30 ++++
 gcc/testsuite/g++.dg/ext/is_member_pointer.C  |  30 ++++
 gcc/testsuite/g++.dg/ext/is_object.C          |  29 ++++
 gcc/testsuite/g++.dg/ext/is_reference.C       |  34 +++++
 gcc/testsuite/g++.dg/ext/is_scoped_enum.C     |  67 +++++++++
 gcc/testsuite/g++.dg/ext/remove_pointer.C     |  51 +++++++
 libstdc++-v3/include/std/type_traits          | 135 +++++++++++++++++-
 21 files changed, 898 insertions(+), 189 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 01/23] c++: Sort built-in traits alphabetically
  2023-12-07  5:32                           ` Ken Matsui
@ 2023-12-07  5:32                             ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 02/23] c-family, c++: Look up built-in traits via identifier node Ken Matsui
                                               ` (21 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch sorts built-in traits alphabetically for better code
readability.

gcc/cp/ChangeLog:

	* constraint.cc (diagnose_trait_expr): Sort built-in traits
	alphabetically.
	* cp-trait.def: Likewise.
	* semantics.cc (trait_expr_value): Likewise.
	(finish_trait_expr): Likewise.
	(finish_trait_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Sort built-in traits alphabetically.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     | 68 ++++++++---------
 gcc/cp/cp-trait.def                      | 10 +--
 gcc/cp/semantics.cc                      | 94 ++++++++++++------------
 gcc/testsuite/g++.dg/ext/has-builtin-1.C | 70 +++++++++---------
 4 files changed, 121 insertions(+), 121 deletions(-)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d9972d69725..29aa7bb3df8 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3707,18 +3707,36 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       inform (loc, "  %qT is not trivially destructible", t1);
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      inform (loc, "  %qT does not have unique object representations", t1);
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       inform (loc, "  %qT does not have a virtual destructor", t1);
       break;
     case CPTK_IS_ABSTRACT:
       inform (loc, "  %qT is not an abstract class", t1);
       break;
+    case CPTK_IS_AGGREGATE:
+      inform (loc, "  %qT is not an aggregate", t1);
+      break;
+    case CPTK_IS_ASSIGNABLE:
+      inform (loc, "  %qT is not assignable from %qT", t1, t2);
+      break;
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
+    case CPTK_IS_CONSTRUCTIBLE:
+      if (!t2)
+    inform (loc, "  %qT is not default constructible", t1);
+      else
+    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_CONVERTIBLE:
+      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_EMPTY:
       inform (loc, "  %qT is not an empty class", t1);
       break;
@@ -3734,6 +3752,18 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      if (!t2)
+	inform (loc, "  %qT is not nothrow default constructible", t1);
+      else
+	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
+      break;
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
@@ -3753,50 +3783,20 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_TRIVIAL:
       inform (loc, "  %qT is not a trivial type", t1);
       break;
-    case CPTK_IS_UNION:
-      inform (loc, "  %qT is not a union", t1);
-      break;
-    case CPTK_IS_AGGREGATE:
-      inform (loc, "  %qT is not an aggregate", t1);
-      break;
-    case CPTK_IS_TRIVIALLY_COPYABLE:
-      inform (loc, "  %qT is not trivially copyable", t1);
-      break;
-    case CPTK_IS_ASSIGNABLE:
-      inform (loc, "  %qT is not assignable from %qT", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       inform (loc, "  %qT is not trivially assignable from %qT", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
-      break;
-    case CPTK_IS_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not default constructible", t1);
-      else
-	inform (loc, "  %qT is not constructible from %qE", t1, t2);
-      break;
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
       if (!t2)
 	inform (loc, "  %qT is not trivially default constructible", t1);
       else
 	inform (loc, "  %qT is not trivially constructible from %qE", t1, t2);
       break;
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      if (!t2)
-	inform (loc, "  %qT is not nothrow default constructible", t1);
-      else
-	inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
-      break;
-    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
-      inform (loc, "  %qT does not have unique object representations", t1);
-      break;
-    case CPTK_IS_CONVERTIBLE:
-      inform (loc, "  %qT is not convertible from %qE", t2, t1);
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      inform (loc, "  %qT is not trivially copyable", t1);
       break;
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-	inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+    case CPTK_IS_UNION:
+      inform (loc, "  %qT is not a union", t1);
       break;
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       inform (loc, "  %qT is not a reference that binds to a temporary "
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 8b7fece0cc8..0e48e64b8dd 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -84,14 +84,14 @@ DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1)
 DEFTRAIT_EXPR (IS_UNION, "__is_union", 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.  */
-DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
-
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
-DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
-DEFTRAIT_TYPE (UNDERLYING_TYPE,  "__underlying_type", 1)
+DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
+DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
+
+/* FIXME Added space to avoid direct usage in GCC 13.  */
+DEFTRAIT_EXPR (IS_DEDUCIBLE, "__is_deducible ", 2)
 
 /* These traits yield a type pack, not a type, and are represented by
    cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree.  */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 6634acfda3f..3abbd6df983 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12303,15 +12303,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		      && classtype_has_nothrow_assign_or_copy_p (type1,
 								 true))));
 
-    case CPTK_HAS_TRIVIAL_ASSIGN:
-      /* ??? The standard seems to be missing the "or array of such a class
-	 type" wording for this trait.  */
-      type1 = strip_array_types (type1);
-      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
-	      && (trivial_type_p (type1)
-		    || (CLASS_TYPE_P (type1)
-			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
-
     case CPTK_HAS_NOTHROW_CONSTRUCTOR:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
@@ -12320,17 +12311,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 		  && maybe_instantiate_noexcept (t)
 		  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
-    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
-      type1 = strip_array_types (type1);
-      return (trivial_type_p (type1)
-	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
-
     case CPTK_HAS_NOTHROW_COPY:
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
 	      || (CLASS_TYPE_P (type1)
 		  && classtype_has_nothrow_assign_or_copy_p (type1, false)));
 
+    case CPTK_HAS_TRIVIAL_ASSIGN:
+      /* ??? The standard seems to be missing the "or array of such a class
+	 type" wording for this trait.  */
+      type1 = strip_array_types (type1);
+      return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+	      && (trivial_type_p (type1)
+		    || (CLASS_TYPE_P (type1)
+			&& TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1))));
+
+    case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+      type1 = strip_array_types (type1);
+      return (trivial_type_p (type1)
+	      || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
     case CPTK_HAS_TRIVIAL_COPY:
       /* ??? The standard seems to be missing the "or array of such a class
 	 type" wording for this trait.  */
@@ -12344,18 +12344,21 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      || (CLASS_TYPE_P (type1)
 		  && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
 
-    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
-      return type_has_virtual_destructor (type1);
-
     case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
       return type_has_unique_obj_representations (type1);
 
+    case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+      return type_has_virtual_destructor (type1);
+
     case CPTK_IS_ABSTRACT:
       return ABSTRACT_CLASS_TYPE_P (type1);
 
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ASSIGNABLE:
+      return is_xible (MODIFY_EXPR, type1, type2);
+
     case CPTK_IS_BASE_OF:
       return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
@@ -12364,6 +12367,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
+    case CPTK_IS_CONSTRUCTIBLE:
+      return is_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_CONVERTIBLE:
+      return is_convertible (type1, type2);
+
     case CPTK_IS_EMPTY:
       return NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1);
 
@@ -12379,6 +12388,15 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      return is_nothrow_xible (INIT_EXPR, type1, type2);
+
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      return is_nothrow_convertible (type1, type2);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12409,24 +12427,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       return type_code1 == UNION_TYPE;
 
-    case CPTK_IS_ASSIGNABLE:
-      return is_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_CONSTRUCTIBLE:
-      return is_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
-      return is_nothrow_xible (MODIFY_EXPR, type1, type2);
-
-    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-      return is_nothrow_xible (INIT_EXPR, type1, type2);
-
-    case CPTK_IS_CONVERTIBLE:
-      return is_convertible (type1, type2);
-
-    case CPTK_IS_NOTHROW_CONVERTIBLE:
-      return is_nothrow_convertible (type1, type2);
-
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
       return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
 
@@ -12539,9 +12539,9 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
     case CPTK_IS_POLYMORPHIC:
-    case CPTK_IS_ABSTRACT:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       if (!check_trait_type (type1, /* kind = */ 3))
 	return error_mark_node;
@@ -12561,12 +12561,12 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
-    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
-    case CPTK_IS_CONVERTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
       if (!check_trait_type (type1)
@@ -12585,8 +12585,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
-    case CPTK_IS_UNION:
     case CPTK_IS_SAME:
+    case CPTK_IS_UNION:
       break;
 
     case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -12649,25 +12649,25 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 
   switch (kind)
     {
-    case CPTK_UNDERLYING_TYPE:
-      return finish_underlying_type (type1);
-
     case CPTK_REMOVE_CV:
       return cv_unqualified (type1);
 
-    case CPTK_REMOVE_REFERENCE:
+    case CPTK_REMOVE_CVREF:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return type1;
+      return cv_unqualified (type1);
 
-    case CPTK_REMOVE_CVREF:
+    case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
-      return cv_unqualified (type1);
+      return type1;
 
     case CPTK_TYPE_PACK_ELEMENT:
       return finish_type_pack_element (type1, type2, complain);
 
+    case CPTK_UNDERLYING_TYPE:
+      return finish_underlying_type (type1);
+
 #define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
     case CPTK_##CODE:
 #include "cp-trait.def"
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index f343e153e56..2223f08a628 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -8,9 +8,21 @@
 #if !__has_builtin (__builtin_bit_cast)
 # error "__has_builtin (__builtin_bit_cast) failed"
 #endif
+#if !__has_builtin (__builtin_is_constant_evaluated)
+# error "__has_builtin (__builtin_is_constant_evaluated) failed"
+#endif
+#if !__has_builtin (__builtin_is_corresponding_member)
+# error "__has_builtin (__builtin_is_corresponding_member) failed"
+#endif
+#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
+# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
+#endif
 #if !__has_builtin (__builtin_launder)
 # error "__has_builtin (__builtin_launder) failed"
 #endif
+#if !__has_builtin (__builtin_source_location)
+# error "__has_builtin (__builtin_source_location) failed"
+#endif
 #if !__has_builtin (__has_nothrow_assign)
 # error "__has_builtin (__has_nothrow_assign) failed"
 #endif
@@ -44,12 +56,21 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_assignable)
+# error "__has_builtin (__is_assignable) failed"
+#endif
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
+#if !__has_builtin (__is_constructible)
+# error "__has_builtin (__is_constructible) failed"
+#endif
+#if !__has_builtin (__is_convertible)
+# error "__has_builtin (__is_convertible) failed"
+#endif
 #if !__has_builtin (__is_empty)
 # error "__has_builtin (__is_empty) failed"
 #endif
@@ -65,6 +86,15 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_nothrow_assignable)
+# error "__has_builtin (__is_nothrow_assignable) failed"
+#endif
+#if !__has_builtin (__is_nothrow_constructible)
+# error "__has_builtin (__is_nothrow_constructible) failed"
+#endif
+#if !__has_builtin (__is_nothrow_convertible)
+# error "__has_builtin (__is_nothrow_convertible) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
@@ -98,51 +128,21 @@
 #if !__has_builtin (__is_union)
 # error "__has_builtin (__is_union) failed"
 #endif
-#if !__has_builtin (__underlying_type)
-# error "__has_builtin (__underlying_type) failed"
-#endif
-#if !__has_builtin (__is_assignable)
-# error "__has_builtin (__is_assignable) failed"
-#endif
-#if !__has_builtin (__is_constructible)
-# error "__has_builtin (__is_constructible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_assignable)
-# error "__has_builtin (__is_nothrow_assignable) failed"
-#endif
-#if !__has_builtin (__is_nothrow_constructible)
-# error "__has_builtin (__is_nothrow_constructible) failed"
-#endif
 #if !__has_builtin (__reference_constructs_from_temporary)
 # error "__has_builtin (__reference_constructs_from_temporary) failed"
 #endif
 #if !__has_builtin (__reference_converts_from_temporary)
 # error "__has_builtin (__reference_converts_from_temporary) failed"
 #endif
-#if !__has_builtin (__builtin_is_constant_evaluated)
-# error "__has_builtin (__builtin_is_constant_evaluated) failed"
-#endif
-#if !__has_builtin (__builtin_source_location)
-# error "__has_builtin (__builtin_source_location) failed"
-#endif
-#if !__has_builtin (__builtin_is_corresponding_member)
-# error "__has_builtin (__builtin_is_corresponding_member) failed"
-#endif
-#if !__has_builtin (__builtin_is_pointer_interconvertible_with_class)
-# error "__has_builtin (__builtin_is_pointer_interconvertible_with_class) failed"
-#endif
-#if !__has_builtin (__is_convertible)
-# error "__has_builtin (__is_convertible) failed"
-#endif
-#if !__has_builtin (__is_nothrow_convertible)
-# error "__has_builtin (__is_nothrow_convertible) failed"
-#endif
 #if !__has_builtin (__remove_cv)
 # error "__has_builtin (__remove_cv) failed"
 #endif
+#if !__has_builtin (__remove_cvref)
+# error "__has_builtin (__remove_cvref) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
-#if !__has_builtin (__remove_cvref)
-# error "__has_builtin (__remove_cvref) failed"
+#if !__has_builtin (__underlying_type)
+# error "__has_builtin (__underlying_type) failed"
 #endif
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 02/23] c-family, c++: Look up built-in traits via identifier node
  2023-12-07  5:32                           ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 01/23] c++: Sort built-in traits alphabetically Ken Matsui
@ 2023-12-07  5:32                             ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 03/23] c++: Accept the use of built-in trait identifiers Ken Matsui
                                               ` (20 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui, Patrick Palka

Since RID_MAX soon reaches 255 and all built-in traits are used
approximately once in a C++ translation unit, this patch removes
all RID values for built-in traits and uses the identifier node to
look up the specific trait.  Rather than holding traits as keywords,
we set all trait identifiers as cik_trait, which is a new
cp_identifier_kind.  As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait.  Also, the later patch handles a subsequent token to the
built-in identifier so that we accept the use of non-function-like
built-in trait identifiers.

gcc/c-family/ChangeLog:

	* c-common.cc (c_common_reswords): Remove all mappings of
	built-in traits.
	* c-common.h (enum rid): Remove all RID values for built-in
	traits.

gcc/cp/ChangeLog:

	* cp-objcp-common.cc (names_builtin_p): Remove all RID value
	cases for built-in traits.  Check for built-in traits via
	the new cik_trait kind.
	* cp-tree.h (enum cp_trait_kind): Set its underlying type to
	addr_space_t.
	(struct cp_trait): New struct to hold trait information.
	(cp_traits): New array to hold a mapping to all traits.
	(cik_reserved_for_udlit): Rename to ...
	(cik_trait): ... this.
	(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
	(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
	* lex.cc (cp_traits): Define its values, declared in cp-tree.h.
	(init_cp_traits): New function to set cik_trait and
	IDENTIFIER_CP_INDEX for all built-in trait identifiers.
	(cxx_init): Call init_cp_traits function.
	* parser.cc (cp_lexer_lookup_trait): New function to look up a
	built-in trait by IDENTIFIER_CP_INDEX.
	(cp_lexer_lookup_trait_expr): Likewise, look up an
	expression-yielding built-in trait.
	(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
	built-in trait.
	(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
	for built-in traits.
	(cp_lexer_next_token_is_decl_specifier_keyword): Handle
	type-yielding built-in traits.
	(cp_parser_primary_expression): Remove all RID value cases for
	built-in traits.  Handle expression-yielding built-in traits.
	(cp_parser_trait): Handle cp_trait instead of enum rid.
	(cp_parser_simple_type_specifier): Remove all RID value cases
	for built-in traits.  Handle type-yielding built-in traits.

Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/c-family/c-common.cc  |   7 ---
 gcc/c-family/c-common.h   |   5 --
 gcc/cp/cp-objcp-common.cc |   8 +--
 gcc/cp/cp-tree.h          |  32 +++++++++---
 gcc/cp/lex.cc             |  34 ++++++++++++
 gcc/cp/parser.cc          | 105 +++++++++++++++++++++++---------------
 6 files changed, 126 insertions(+), 65 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index d175054dddb..0f1de44a348 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -560,13 +560,6 @@ const struct c_common_resword c_common_reswords[] =
   { "wchar_t",		RID_WCHAR,	D_CXXONLY },
   { "while",		RID_WHILE,	0 },
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  { NAME,		RID_##CODE,	D_CXXONLY },
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-  /* An alias for __is_same.  */
-  { "__is_same_as",	RID_IS_SAME,	D_CXXONLY },
-
   /* C++ transactional memory.  */
   { "synchronized",	RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
   { "atomic_noexcept",	RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index cb9b6f301d8..62d76c87cc0 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -168,11 +168,6 @@ enum rid
   RID_BUILTIN_LAUNDER,
   RID_BUILTIN_BIT_CAST,
 
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-  RID_##CODE,
-#include "cp/cp-trait.def"
-#undef DEFTRAIT
-
   /* C++11 */
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 9439c4dc744..ee88df5767b 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -565,6 +565,10 @@ names_builtin_p (const char *name)
 	}
     }
 
+  /* Check for built-in traits.  */
+  if (IDENTIFIER_TRAIT_P (id))
+    return true;
+
   /* Also detect common reserved C++ words that aren't strictly built-in
      functions.  */
   switch (C_RID_CODE (id))
@@ -578,10 +582,6 @@ names_builtin_p (const char *name)
     case RID_BUILTIN_ASSOC_BARRIER:
     case RID_BUILTIN_BIT_CAST:
     case RID_OFFSETOF:
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT
       return true;
     default:
       break;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index cb89d372b23..cbf280ec454 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1237,7 +1237,7 @@ enum cp_identifier_kind {
   cik_simple_op = 4,	/* Non-assignment operator name.  */
   cik_assign_op = 5,	/* An assignment operator name.  */
   cik_conv_op = 6,	/* Conversion operator name.  */
-  cik_reserved_for_udlit = 7,	/* Not yet in use  */
+  cik_trait = 7,	/* Built-in trait name.  */
   cik_max
 };
 
@@ -1282,9 +1282,9 @@ enum cp_identifier_kind {
     & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is for any operator name (including
-   conversions).  Value 4, 5, 6 or 7.  */
+   conversions).  Value 4, 5, or 6.  */
 #define IDENTIFIER_ANY_OP_P(NODE)		\
-  (IDENTIFIER_KIND_BIT_2 (NODE))
+  (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
 
 /* True if this identifier is for an overloaded operator. Values 4, 5.  */
 #define IDENTIFIER_OVL_OP_P(NODE)		\
@@ -1297,12 +1297,18 @@ enum cp_identifier_kind {
    & IDENTIFIER_KIND_BIT_0 (NODE))
 
 /* True if this identifier is the name of a type-conversion
-   operator.  Value 7.  */
+   operator.  Value 6.  */
 #define IDENTIFIER_CONV_OP_P(NODE)		\
   (IDENTIFIER_ANY_OP_P (NODE)			\
    & IDENTIFIER_KIND_BIT_1 (NODE)		\
    & (!IDENTIFIER_KIND_BIT_0 (NODE)))
 
+/* True if this identifier is the name of a built-in trait.  */
+#define IDENTIFIER_TRAIT_P(NODE)		\
+  (IDENTIFIER_KIND_BIT_0 (NODE)			\
+   & IDENTIFIER_KIND_BIT_1 (NODE)		\
+   & IDENTIFIER_KIND_BIT_2 (NODE))
+
 /* True if this identifier is a new or delete operator.  */
 #define IDENTIFIER_NEWDEL_OP_P(NODE)		\
   (IDENTIFIER_OVL_OP_P (NODE)			\
@@ -1386,16 +1392,26 @@ struct GTY (()) tree_argument_pack_select {
   int index;
 };
 
-/* The different kinds of traits that we encounter.  */
-
-enum cp_trait_kind
-{
+/* The different kinds of traits that we encounter.  The size is limited to
+   addr_space_t since a trait is looked up by IDENTIFIER_CP_INDEX.  */
+enum cp_trait_kind : addr_space_t {
 #define DEFTRAIT(TCC, CODE, NAME, ARITY) \
   CPTK_##CODE,
 #include "cp-trait.def"
 #undef DEFTRAIT
 };
 
+/* The trait type.  */
+struct cp_trait {
+  const char *name;
+  cp_trait_kind kind;
+  short arity;
+  bool type;
+};
+
+/* The trait table indexed by cp_trait_kind.  */
+extern const struct cp_trait cp_traits[];
+
 /* The types that we are processing.  */
 #define TRAIT_EXPR_TYPE1(NODE) \
   (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1)
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 64bcfb18196..a939e2e5f13 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 
 static int interface_strcmp (const char *);
+static void init_cp_traits (void);
 static void init_cp_pragma (void);
 
 static tree parse_strconst_pragma (const char *, int);
@@ -97,6 +98,19 @@ ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
 unsigned char ovl_op_mapping[MAX_TREE_CODES];
 unsigned char ovl_op_alternate[OVL_OP_MAX];
 
+/* The trait table, declared in cp-tree.h.  */
+const cp_trait cp_traits[] =
+{
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+  { NAME, CPTK_##CODE, ARITY, (TCC == tcc_type) },
+#include "cp-trait.def"
+#undef DEFTRAIT
+};
+/* The trait table cannot have more than 255 (addr_space_t) entries since
+   the index is retrieved through IDENTIFIER_CP_INDEX.  */
+static_assert(ARRAY_SIZE (cp_traits) <= 255,
+	      "cp_traits array cannot have more than 255 entries");
+
 /* Get the name of the kind of identifier T.  */
 
 const char *
@@ -283,6 +297,25 @@ init_reswords (void)
     }
 }
 
+/* Initialize the C++ traits.  */
+static void
+init_cp_traits (void)
+{
+  tree id;
+
+  for (unsigned int i = 0; i < ARRAY_SIZE (cp_traits); ++i)
+    {
+      id = get_identifier (cp_traits[i].name);
+      IDENTIFIER_CP_INDEX (id) = cp_traits[i].kind;
+      set_identifier_kind (id, cik_trait);
+    }
+
+  /* An alias for __is_same.  */
+  id = get_identifier ("__is_same_as");
+  IDENTIFIER_CP_INDEX (id) = CPTK_IS_SAME;
+  set_identifier_kind (id, cik_trait);
+}
+
 static void
 init_cp_pragma (void)
 {
@@ -324,6 +357,7 @@ cxx_init (void)
   input_location = BUILTINS_LOCATION;
 
   init_reswords ();
+  init_cp_traits ();
   init_tree ();
   init_cp_semantics ();
   init_operators ();
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 732d2a919eb..a416b58a2a5 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,6 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+  (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+  (const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1173,12 +1179,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     case RID_CONSTEVAL:
       return true;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      return true;
-
     default:
       if (keyword >= RID_FIRST_INT_N
 	  && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1188,6 +1188,44 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
+/* Look ups the corresponding built-in trait if a given token is
+   a built-in trait.  Otherwise, returns nullptr.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
+    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && !trait->type)
+    return trait;
+
+  return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+   built-in trait.  */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  if (trait && trait->type)
+    return trait;
+
+  return nullptr;
+}
+
 /* Return true if the next token is a keyword for a decl-specifier.  */
 
 static bool
@@ -1196,6 +1234,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
+  if (cp_lexer_lookup_trait_type (token))
+    return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -2861,7 +2901,7 @@ static void cp_parser_late_parsing_default_args
 static tree cp_parser_sizeof_operand
   (cp_parser *, enum rid);
 static cp_expr cp_parser_trait
-  (cp_parser *, enum rid);
+  (cp_parser *, const cp_trait *);
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
@@ -6055,12 +6095,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_OFFSETOF:
 	  return cp_parser_builtin_offsetof (parser);
 
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
-	case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
-	  return cp_parser_trait (parser, token->keyword);
-
 	// C++ concepts
 	case RID_REQUIRES:
 	  return cp_parser_requires_expression (parser);
@@ -6099,6 +6133,9 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
+      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+	return cp_parser_trait (parser, trait);
+      /* FALLTHRU */
     case CPP_SCOPE:
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
@@ -11029,28 +11066,13 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 /* Parse a builtin trait expression or type.  */
 
 static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
 {
-  cp_trait_kind kind;
+  const cp_trait_kind kind = trait->kind;
   tree type1, type2 = NULL_TREE;
-  bool binary = false;
-  bool variadic = false;
-  bool type = false;
-
-  switch (keyword)
-    {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
-    case RID_##CODE:			 \
-      kind = CPTK_##CODE;		 \
-      binary = (ARITY == 2);		 \
-      variadic = (ARITY == -1);		 \
-      type = (TCC == tcc_type);		 \
-      break;
-#include "cp-trait.def"
-#undef DEFTRAIT
-    default:
-      gcc_unreachable ();
-    }
+  const bool binary = (trait->arity == 2);
+  const bool variadic = (trait->arity == -1);
+  const bool type = trait->type;
 
   /* Get location of initial token.  */
   location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -20124,20 +20146,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       return type;
 
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
-    case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
-      type = cp_parser_trait (parser, token->keyword);
+    default:
+      break;
+    }
+
+  /* If token is a type-yielding built-in traits, parse it.  */
+  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  if (trait)
+    {
+      type = cp_parser_trait (parser, trait);
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
 				      token,
 				      /*type_definition_p=*/false);
 
       return type;
-
-    default:
-      break;
     }
 
   /* If token is an already-parsed decltype not followed by ::,
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 03/23] c++: Accept the use of built-in trait identifiers
  2023-12-07  5:32                           ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 01/23] c++: Sort built-in traits alphabetically Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 02/23] c-family, c++: Look up built-in traits via identifier node Ken Matsui
@ 2023-12-07  5:32                             ` Ken Matsui
  2023-12-07  5:32                             ` [PATCH v26 04/23] c++: Implement __is_array built-in trait Ken Matsui
                                               ` (19 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent
token is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 53 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a416b58a2a5..bf5add5cae9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@ static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1188,15 +1188,29 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
-   a built-in trait.  Otherwise, returns nullptr.  */
+/* Peeks the corresponding built-in trait if the first token is
+   a built-in trait and the second token is either `(' or `<' depending
+   on the trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  const cp_token *token1 = cp_lexer_peek_token (lexer);
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+	 __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1204,9 +1218,9 @@ cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer);
   if (trait && !trait->type)
     return trait;
 
@@ -1217,9 +1231,9 @@ cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer);
   if (trait && trait->type)
     return trait;
 
@@ -1233,9 +1247,10 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
 {
   cp_token *token;
 
-  token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer))
     return true;
+
+  token = cp_lexer_peek_token (lexer);
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
 
@@ -6133,7 +6148,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait = cp_lexer_peek_trait_expr (parser->lexer))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20151,7 +20166,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 04/23] c++: Implement __is_array built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (2 preceding siblings ...)
  2023-12-07  5:32                             ` [PATCH v26 03/23] c++: Accept the use of built-in trait identifiers Ken Matsui
@ 2023-12-07  5:32                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 05/23] libstdc++: Optimize std::is_array compilation performance Ken Matsui
                                               ` (18 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_array.
	* g++.dg/ext/is_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_array.C      | 28 ++++++++++++++++++++++++
 5 files changed, 39 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 29aa7bb3df8..d75132e8e82 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3719,6 +3719,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_AGGREGATE:
       inform (loc, "  %qT is not an aggregate", t1);
       break;
+    case CPTK_IS_ARRAY:
+      inform (loc, "  %qT is not an array", t1);
+      break;
     case CPTK_IS_ASSIGNABLE:
       inform (loc, "  %qT is not assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e48e64b8dd..759f10a3532 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -59,6 +59,7 @@ DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representati
 DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1)
 DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1)
 DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
+DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 3abbd6df983..aa551638a78 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12356,6 +12356,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_AGGREGATE:
       return CP_AGGREGATE_TYPE_P (type1);
 
+    case CPTK_IS_ARRAY:
+      return type_code1 == ARRAY_TYPE;
+
     case CPTK_IS_ASSIGNABLE:
       return is_xible (MODIFY_EXPR, type1, type2);
 
@@ -12583,6 +12586,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
+    case CPTK_IS_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2223f08a628..6b9437f7c47 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -56,6 +56,9 @@
 #if !__has_builtin (__is_aggregate)
 # error "__has_builtin (__is_aggregate) failed"
 #endif
+#if !__has_builtin (__is_array)
+# error "__has_builtin (__is_array) failed"
+#endif
 #if !__has_builtin (__is_assignable)
 # error "__has_builtin (__is_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_array.C b/gcc/testsuite/g++.dg/ext/is_array.C
new file mode 100644
index 00000000000..facfed5c7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_array.C
@@ -0,0 +1,28 @@
+// { 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, X, expect) \
+  SA(TRAIT(X) == expect);                  \
+  SA(TRAIT(const X) == expect);            \
+  SA(TRAIT(volatile X) == expect);         \
+  SA(TRAIT(const volatile X) == expect)
+
+SA_TEST_CATEGORY(__is_array, int[2], true);
+SA_TEST_CATEGORY(__is_array, int[], true);
+SA_TEST_CATEGORY(__is_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_array, int[][3], true);
+SA_TEST_CATEGORY(__is_array, float*[2], true);
+SA_TEST_CATEGORY(__is_array, float*[], true);
+SA_TEST_CATEGORY(__is_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_array, float*[][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_array, ClassType[], true);
+SA_TEST_CATEGORY(__is_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_array, ClassType[][3], true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_array, ClassType, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 05/23] libstdc++: Optimize std::is_array compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (3 preceding siblings ...)
  2023-12-07  5:32                             ` [PATCH v26 04/23] c++: Implement __is_array built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 06/23] c++: Implement __is_bounded_array built-in trait Ken Matsui
                                               ` (17 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_array
by dispatching to the new __is_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_array): Use __is_array built-in
	trait.
	(is_array_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 677cd934b94..64f9d67fe29 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -523,6 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_array
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+  template<typename _Tp>
+    struct is_array
+    : public __bool_constant<__is_array(_Tp)>
+    { };
+#else
   template<typename>
     struct is_array
     : public false_type { };
@@ -534,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_array<_Tp[]>
     : public true_type { };
+#endif
 
   template<typename>
     struct __is_pointer_helper
@@ -3169,12 +3176,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_array)
+template <typename _Tp>
+  inline constexpr bool is_array_v = __is_array(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_array_v = false;
 template <typename _Tp>
   inline constexpr bool is_array_v<_Tp[]> = true;
 template <typename _Tp, size_t _Num>
   inline constexpr bool is_array_v<_Tp[_Num]> = true;
+#endif
 
 template <typename _Tp>
   inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 06/23] c++: Implement __is_bounded_array built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (4 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 05/23] libstdc++: Optimize std::is_array compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 07/23] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
                                               ` (16 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_bounded_array.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_bounded_array.
	* g++.dg/ext/is_bounded_array.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_bounded_array.C | 38 +++++++++++++++++++++
 5 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_bounded_array.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d75132e8e82..2311bab28c4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3728,6 +3728,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_BASE_OF:
       inform (loc, "  %qT is not a base of %qT", t1, t2);
       break;
+    case CPTK_IS_BOUNDED_ARRAY:
+      inform (loc, "  %qT is not a bounded array", t1);
+      break;
     case CPTK_IS_CLASS:
       inform (loc, "  %qT is not a class", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 759f10a3532..0e93e2b7114 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -62,6 +62,7 @@ DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1)
 DEFTRAIT_EXPR (IS_ARRAY, "__is_array", 1)
 DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2)
 DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2)
+DEFTRAIT_EXPR (IS_BOUNDED_ARRAY, "__is_bounded_array", 1)
 DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1)
 DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1)
 DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index aa551638a78..e3ea835a6b1 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12367,6 +12367,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 	      && (same_type_ignoring_top_level_qualifiers_p (type1, type2)
 		  || DERIVED_FROM_P (type1, type2)));
 
+    case CPTK_IS_BOUNDED_ARRAY:
+      return type_code1 == ARRAY_TYPE && TYPE_DOMAIN (type1);
+
     case CPTK_IS_CLASS:
       return NON_UNION_CLASS_TYPE_P (type1);
 
@@ -12587,6 +12590,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
       break;
 
     case CPTK_IS_ARRAY:
+    case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 6b9437f7c47..4cfb817788c 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -65,6 +65,9 @@
 #if !__has_builtin (__is_base_of)
 # error "__has_builtin (__is_base_of) failed"
 #endif
+#if !__has_builtin (__is_bounded_array)
+# error "__has_builtin (__is_bounded_array) failed"
+#endif
 #if !__has_builtin (__is_class)
 # error "__has_builtin (__is_class) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_bounded_array.C b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
new file mode 100644
index 00000000000..346790eba12
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_bounded_array.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_CONST(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_bounded_array, int[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, int[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[], false);
+SA_TEST_CATEGORY(__is_bounded_array, float*[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, float*[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[], false);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[2][3], true);
+SA_TEST_CATEGORY(__is_bounded_array, ClassType[][3], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[2], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(*)[], false);
+SA_TEST_CATEGORY(__is_bounded_array, int(&)[2], false);
+SA_TEST_CONST(__is_bounded_array, int(&)[], false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_bounded_array, ClassType, false);
+SA_TEST_CONST(__is_bounded_array, void(), false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 07/23] libstdc++: Optimize std::is_bounded_array compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (5 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 06/23] c++: Implement __is_bounded_array built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 08/23] c++: Implement __is_scoped_enum built-in trait Ken Matsui
                                               ` (15 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_bounded_array
by dispatching to the new __is_bounded_array built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_bounded_array_v): Use
	__is_bounded_array built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 64f9d67fe29..2a1a0aa80ff 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3506,11 +3506,16 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True for a type that is an array of known bound.
   /// @ingroup variable_templates
   /// @since C++20
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_bounded_array)
+  template<typename _Tp>
+    inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_bounded_array_v = false;
 
   template<typename _Tp, size_t _Size>
     inline constexpr bool is_bounded_array_v<_Tp[_Size]> = true;
+# endif
 
   /// True for a type that is an array of unknown bound.
   /// @ingroup variable_templates
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 08/23] c++: Implement __is_scoped_enum built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (6 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 07/23] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 09/23] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
                                               ` (14 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_scoped_enum.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_scoped_enum.
	* g++.dg/ext/is_scoped_enum.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_scoped_enum.C | 67 +++++++++++++++++++++++
 5 files changed, 78 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_scoped_enum.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2311bab28c4..062dc404ccf 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3783,6 +3783,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
+    case CPTK_IS_SCOPED_ENUM:
+      inform (loc, "  %qT is not a scoped enum", t1);
+      break;
     case CPTK_IS_STD_LAYOUT:
       inform (loc, "  %qT is not an standard layout type", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 0e93e2b7114..9d848f6f77d 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -78,6 +78,7 @@ DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertib
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
+DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
 DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1)
 DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e3ea835a6b1..ea85da3b41a 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12415,6 +12415,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
+    case CPTK_IS_SCOPED_ENUM:
+      return SCOPED_ENUM_P (type1);
+
     case CPTK_IS_STD_LAYOUT:
       return std_layout_type_p (type1);
 
@@ -12594,6 +12597,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
     case CPTK_IS_SAME:
+    case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNION:
       break;
 
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 4cfb817788c..744cfb3b42f 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -116,6 +116,9 @@
 #if !__has_builtin (__is_same_as)
 # error "__has_builtin (__is_same_as) failed"
 #endif
+#if !__has_builtin (__is_scoped_enum)
+# error "__has_builtin (__is_scoped_enum) failed"
+#endif
 #if !__has_builtin (__is_standard_layout)
 # error "__has_builtin (__is_standard_layout) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_scoped_enum.C b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
new file mode 100644
index 00000000000..a563b6ee67d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_scoped_enum.C
@@ -0,0 +1,67 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+enum class E { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, E, true);
+enum class Ec : char { e1, e2 };
+SA_TEST_CATEGORY(__is_scoped_enum, Ec, true);
+
+// negative tests
+enum U { u1, u2 };
+SA_TEST_CATEGORY(__is_scoped_enum, U, false);
+enum F : int { f1, f2 };
+SA_TEST_CATEGORY(__is_scoped_enum, F, false);
+struct S;
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+struct S { };
+SA_TEST_CATEGORY(__is_scoped_enum, S, false);
+
+SA_TEST_CATEGORY(__is_scoped_enum, int, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[][2], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int[2][3], false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int&, false);
+SA_TEST_CATEGORY(__is_scoped_enum, int*&, false);
+SA_TEST_FN(__is_scoped_enum, int(), false);
+SA_TEST_FN(__is_scoped_enum, int(*)(), false);
+SA_TEST_FN(__is_scoped_enum, int(&)(), false);
+
+enum opaque_unscoped : short;
+enum class opaque_scoped;
+enum class opaque_scoped_with_base : long;
+
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_unscoped, false);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped, true);
+SA_TEST_CATEGORY(__is_scoped_enum, opaque_scoped_with_base, true);
+
+enum unscoped {
+  u_is_scoped = __is_scoped_enum(unscoped),
+};
+SA( ! unscoped::u_is_scoped );
+
+enum unscoped_fixed : char {
+  uf_is_scoped = __is_scoped_enum(unscoped_fixed),
+};
+SA( ! unscoped_fixed::uf_is_scoped );
+
+enum class scoped {
+  is_scoped = __is_scoped_enum(scoped),
+};
+SA( (bool) scoped::is_scoped );
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 09/23] libstdc++: Optimize std::is_scoped_enum compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (7 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 08/23] c++: Implement __is_scoped_enum built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 10/23] c++: Implement __is_member_pointer built-in trait Ken Matsui
                                               ` (13 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_scoped_enum
by dispatching to the new __is_scoped_enum built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Use
	__is_scoped_enum built-in trait.
	(is_scoped_enum_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 2a1a0aa80ff..4a5068791af 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3602,6 +3602,12 @@ template<typename _Ret, typename _Fn, typename... _Args>
   /// True if the type is a scoped enumeration type.
   /// @since C++23
 
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    struct is_scoped_enum
+    : bool_constant<__is_scoped_enum(_Tp)>
+    { };
+# else
   template<typename _Tp>
     struct is_scoped_enum
     : false_type
@@ -3613,11 +3619,17 @@ template<typename _Ret, typename _Fn, typename... _Args>
     struct is_scoped_enum<_Tp>
     : bool_constant<!requires(_Tp __t, void(*__f)(int)) { __f(__t); }>
     { };
+# endif
 
   /// @ingroup variable_templates
   /// @since C++23
+# if _GLIBCXX_USE_BUILTIN_TRAIT(__is_scoped_enum)
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+# else
   template<typename _Tp>
     inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+# endif
 #endif
 
 #ifdef __cpp_lib_reference_from_temporary // C++ >= 23 && ref_{converts,constructs}_from_temp
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 10/23] c++: Implement __is_member_pointer built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (8 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 09/23] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 11/23] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
                                               ` (12 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_pointer.
	* g++.dg/ext/is_member_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_member_pointer.C | 30 ++++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 062dc404ccf..fb150e02ea9 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3758,6 +3758,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_POINTER:
+      inform (loc, "  %qT is not a member pointer", t1);
+      break;
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       inform (loc, "  %qT is not nothrow assignable from %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9d848f6f77d..e17f5eaeac4 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index ea85da3b41a..050808b96b9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12394,6 +12394,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_POINTER:
+      return TYPE_PTRMEM_P (type1);
+
     case CPTK_IS_NOTHROW_ASSIGNABLE:
       return is_nothrow_xible (MODIFY_EXPR, type1, type2);
 
@@ -12596,6 +12599,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 744cfb3b42f..349fae7104e 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -92,6 +92,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_pointer)
+# error "__has_builtin (__is_member_pointer) failed"
+#endif
 #if !__has_builtin (__is_nothrow_assignable)
 # error "__has_builtin (__is_nothrow_assignable) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
new file mode 100644
index 00000000000..7ee2e3ab90c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_member_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_pointer, ClassType (ClassType::*), true);
+
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(int) const, true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, int (ClassType::*)(float, ...), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer, ClassType (ClassType::*)(ClassType), true);
+SA_TEST_NON_VOLATILE(__is_member_pointer,
+        float (ClassType::*)(int, float, int[], int&), true);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_pointer, ClassType, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 11/23] libstdc++: Optimize std::is_member_pointer compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (9 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 10/23] c++: Implement __is_member_pointer built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 12/23] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
                                               ` (11 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_member_pointer
by dispatching to the new __is_member_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_pointer): Use
	__is_member_pointer built-in trait.
	(is_member_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4a5068791af..4ab1d29ff51 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -716,6 +716,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_compound
     : public __not_<is_fundamental<_Tp>>::type { };
 
+  /// is_member_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+  template<typename _Tp>
+    struct is_member_pointer
+    : public __bool_constant<__is_member_pointer(_Tp)>
+    { };
+#else
   /// @cond undocumented
   template<typename _Tp>
     struct __is_member_pointer_helper
@@ -726,11 +733,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
   /// @endcond
 
-  /// is_member_pointer
   template<typename _Tp>
     struct is_member_pointer
     : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   template<typename, typename>
     struct is_same;
@@ -3228,8 +3235,15 @@ template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 12/23] c++: Implement __is_member_function_pointer built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (10 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 11/23] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 13/23] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
                                               ` (10 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_function_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_function_pointer.
	* g++.dg/ext/is_member_function_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_function_pointer.C   | 31 +++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_function_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index fb150e02ea9..1efc7983039 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3758,6 +3758,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_LITERAL_TYPE:
       inform (loc, "  %qT is not a literal type", t1);
       break;
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      inform (loc, "  %qT is not a member function pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index e17f5eaeac4..03a5cc28020 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -71,6 +71,7 @@ DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
+DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 050808b96b9..eefce24ac2c 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12394,6 +12394,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_LITERAL_TYPE:
       return literal_type_p (type1);
 
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
+      return TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12599,6 +12602,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
+    case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 349fae7104e..fb17680d3b0 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -92,6 +92,9 @@
 #if !__has_builtin (__is_literal_type)
 # error "__has_builtin (__is_literal_type) failed"
 #endif
+#if !__has_builtin (__is_member_function_pointer)
+# error "__has_builtin (__is_member_function_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
new file mode 100644
index 00000000000..555123e8f07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_function_pointer.C
@@ -0,0 +1,31 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_FN(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);			\
+  SA(TRAIT(const TYPE) == EXPECT);
+
+#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)
+
+// Positive tests.
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int), true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (int) const, true);
+SA_TEST_FN(__is_member_function_pointer, int (ClassType::*) (float, ...), true);
+SA_TEST_FN(__is_member_function_pointer, ClassType (ClassType::*) (ClassType), true);
+SA_TEST_FN(__is_member_function_pointer, float (ClassType::*) (int, float, int[], int&), true);
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_member_function_pointer, int (ClassType::*), false);
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType (ClassType::*), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_function_pointer, ClassType, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 13/23] libstdc++: Optimize std::is_member_function_pointer compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (11 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 12/23] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 14/23] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
                                               ` (9 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_function_pointer by dispatching to the new
__is_member_function_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_function_pointer): Use
	__is_member_function_pointer built-in trait.
	(is_member_function_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4ab1d29ff51..99ae825301c 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -588,6 +588,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
 
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+  /// is_member_function_pointer
+  template<typename _Tp>
+    struct is_member_function_pointer
+    : public __bool_constant<__is_member_function_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_function_pointer_helper
     : public false_type { };
@@ -601,6 +608,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_member_function_pointer
     : public __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
   /// is_enum
   template<typename _Tp>
@@ -3208,9 +3216,17 @@ template <typename _Tp>
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_function_pointer_v =
+    __is_member_function_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_function_pointer_v =
     is_member_function_pointer<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_enum_v = __is_enum(_Tp);
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 14/23] c++: Implement __is_member_object_pointer built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (12 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 13/23] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 15/23] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
                                               ` (8 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_member_object_pointer.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of
	__is_member_object_pointer.
	* g++.dg/ext/is_member_object_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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 ++
 .../g++.dg/ext/is_member_object_pointer.C     | 30 +++++++++++++++++++
 5 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_member_object_pointer.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 1efc7983039..204b9989b6a 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3761,6 +3761,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       inform (loc, "  %qT is not a member function pointer", t1);
       break;
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      inform (loc, "  %qT is not a member object pointer", t1);
+      break;
     case CPTK_IS_MEMBER_POINTER:
       inform (loc, "  %qT is not a member pointer", t1);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 03a5cc28020..f5efffdfc99 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -72,6 +72,7 @@ DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
+DEFTRAIT_EXPR (IS_MEMBER_OBJECT_POINTER, "__is_member_object_pointer", 1)
 DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index eefce24ac2c..557642d6089 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12397,6 +12397,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
       return TYPE_PTRMEMFUNC_P (type1);
 
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
+      return TYPE_PTRMEM_P (type1) && !TYPE_PTRMEMFUNC_P (type1);
+
     case CPTK_IS_MEMBER_POINTER:
       return TYPE_PTRMEM_P (type1);
 
@@ -12603,6 +12606,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
+    case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index fb17680d3b0..b5797075d52 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -95,6 +95,9 @@
 #if !__has_builtin (__is_member_function_pointer)
 # error "__has_builtin (__is_member_function_pointer) failed"
 #endif
+#if !__has_builtin (__is_member_object_pointer)
+# error "__has_builtin (__is_member_object_pointer) failed"
+#endif
 #if !__has_builtin (__is_member_pointer)
 # error "__has_builtin (__is_member_pointer) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
new file mode 100644
index 00000000000..835e48c8f8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_member_object_pointer.C
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);						\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_member_object_pointer, int (ClassType::*), true);
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType (ClassType::*), true);
+
+// Negative tests.
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (int), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, int (ClassType::*) (float, ...), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, ClassType (ClassType::*) (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_member_object_pointer, float (ClassType::*) (int, float, int[], int&), false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_member_object_pointer, ClassType, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 15/23] libstdc++: Optimize std::is_member_object_pointer compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (13 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 14/23] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 16/23] c++: Implement __is_reference built-in trait Ken Matsui
                                               ` (7 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of
std::is_member_object_pointer by dispatching to the new
__is_member_object_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_member_object_pointer): Use
	__is_member_object_pointer built-in trait.
	(is_member_object_pointer_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 99ae825301c..1edd05acb4c 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -574,6 +574,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_rvalue_reference<_Tp&&>
     : public true_type { };
 
+  /// is_member_object_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+  template<typename _Tp>
+    struct is_member_object_pointer
+    : public __bool_constant<__is_member_object_pointer(_Tp)>
+    { };
+#else
   template<typename>
     struct __is_member_object_pointer_helper
     : public false_type { };
@@ -582,11 +589,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_member_object_pointer_helper<_Tp _Cp::*>
     : public __not_<is_function<_Tp>>::type { };
 
-  /// is_member_object_pointer
+
   template<typename _Tp>
     struct is_member_object_pointer
     : public __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type
     { };
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
   /// is_member_function_pointer
@@ -3213,9 +3221,16 @@ template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_rvalue_reference_v<_Tp&&> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_object_pointer)
+template <typename _Tp>
+  inline constexpr bool is_member_object_pointer_v =
+    __is_member_object_pointer(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_member_object_pointer_v =
     is_member_object_pointer<_Tp>::value;
+#endif
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_member_function_pointer)
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 16/23] c++: Implement __is_reference built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (14 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 15/23] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 17/23] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
                                               ` (6 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_reference.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_reference.
	* g++.dg/ext/is_reference.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_reference.C  | 34 ++++++++++++++++++++++++
 5 files changed, 45 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_reference.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 204b9989b6a..aa42017f67c 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3789,6 +3789,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_POLYMORPHIC:
       inform (loc, "  %qT is not a polymorphic type", t1);
       break;
+    case CPTK_IS_REFERENCE:
+      inform (loc, "  %qT is not a reference", t1);
+      break;
     case CPTK_IS_SAME:
       inform (loc, "  %qT is not the same as %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index f5efffdfc99..2d82ed3dd35 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -80,6 +80,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
+DEFTRAIT_EXPR (IS_REFERENCE, "__is_reference", 1)
 DEFTRAIT_EXPR (IS_SAME, "__is_same", 2)
 DEFTRAIT_EXPR (IS_SCOPED_ENUM, "__is_scoped_enum", 1)
 DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 557642d6089..b637798f605 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12421,6 +12421,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
       return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1);
 
+    case CPTK_IS_REFERENCE:
+      return type_code1 == REFERENCE_TYPE;
+
     case CPTK_IS_SAME:
       return same_type_p (type1, type2);
 
@@ -12608,6 +12611,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
     case CPTK_IS_UNION:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b5797075d52..b667b5c33ac 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -119,6 +119,9 @@
 #if !__has_builtin (__is_polymorphic)
 # error "__has_builtin (__is_polymorphic) failed"
 #endif
+#if !__has_builtin (__is_reference)
+# error "__has_builtin (__is_reference) failed"
+#endif
 #if !__has_builtin (__is_same)
 # error "__has_builtin (__is_same) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_reference.C b/gcc/testsuite/g++.dg/ext/is_reference.C
new file mode 100644
index 00000000000..b5ce4db7afd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_reference.C
@@ -0,0 +1,34 @@
+// { 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)
+
+// Positive tests.
+SA_TEST_CATEGORY(__is_reference, int&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&, true);
+SA(__is_reference(int(&)(int)));
+SA_TEST_CATEGORY(__is_reference, int&&, true);
+SA_TEST_CATEGORY(__is_reference, ClassType&&, true);
+SA(__is_reference(int(&&)(int)));
+SA_TEST_CATEGORY(__is_reference, IncompleteClass&, true);
+
+// Negative tests
+SA_TEST_CATEGORY(__is_reference, void, false);
+SA_TEST_CATEGORY(__is_reference, int*, false);
+SA_TEST_CATEGORY(__is_reference, int[3], false);
+SA(!__is_reference(int(int)));
+SA(!__is_reference(int(*const)(int)));
+SA(!__is_reference(int(*volatile)(int)));
+SA(!__is_reference(int(*const volatile)(int)));
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_reference, ClassType, false);
+SA_TEST_CATEGORY(__is_reference, IncompleteClass, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 17/23] libstdc++: Optimize std::is_reference compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (15 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 16/23] c++: Implement __is_reference built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 18/23] c++: Implement __is_function built-in trait Ken Matsui
                                               ` (5 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_reference
by dispatching to the new __is_reference built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_reference): Use __is_reference
	built-in trait.
	(is_reference_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 1edd05acb4c..db880d87f60 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -682,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Composite type categories.
 
   /// is_reference
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+  template<typename _Tp>
+    struct is_reference
+    : public __bool_constant<__is_reference(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_reference
     : public false_type
@@ -696,6 +702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_reference<_Tp&&>
     : public true_type
     { };
+#endif
 
   /// is_arithmetic
   template<typename _Tp>
@@ -3250,12 +3257,19 @@ template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
 template <typename _Tp>
   inline constexpr bool is_function_v = is_function<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
+template <typename _Tp>
+  inline constexpr bool is_reference_v = __is_reference(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_reference_v = false;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&> = true;
 template <typename _Tp>
   inline constexpr bool is_reference_v<_Tp&&> = true;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 18/23] c++: Implement __is_function built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (16 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 17/23] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 19/23] libstdc++: Optimize std::is_function compilation performance Ken Matsui
                                               ` (4 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_function.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_function.
	* g++.dg/ext/is_function.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 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_function.C   | 58 ++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_function.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index aa42017f67c..4bea6089791 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3752,6 +3752,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_FINAL:
       inform (loc, "  %qT is not a final class", t1);
       break;
+    case CPTK_IS_FUNCTION:
+      inform (loc, "  %qT is not a function", t1);
+      break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
       break;
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 2d82ed3dd35..89712f18667 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -69,6 +69,7 @@ DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2)
 DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1)
 DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1)
 DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1)
+DEFTRAIT_EXPR (IS_FUNCTION, "__is_function", 1)
 DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2)
 DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1)
 DEFTRAIT_EXPR (IS_MEMBER_FUNCTION_POINTER, "__is_member_function_pointer", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index b637798f605..50330922d70 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12388,6 +12388,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_FINAL:
       return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1);
 
+    case CPTK_IS_FUNCTION:
+      return type_code1 == FUNCTION_TYPE;
+
     case CPTK_IS_LAYOUT_COMPATIBLE:
       return layout_compatible_type_p (type1, type2);
 
@@ -12608,6 +12611,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_BOUNDED_ARRAY:
     case CPTK_IS_CLASS:
     case CPTK_IS_ENUM:
+    case CPTK_IS_FUNCTION:
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index b667b5c33ac..5215da27d6f 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -86,6 +86,9 @@
 #if !__has_builtin (__is_final)
 # error "__has_builtin (__is_final) failed"
 #endif
+#if !__has_builtin (__is_function)
+# error "__has_builtin (__is_function) failed"
+#endif
 #if !__has_builtin (__is_layout_compatible)
 # error "__has_builtin (__is_layout_compatible) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_function.C b/gcc/testsuite/g++.dg/ext/is_function.C
new file mode 100644
index 00000000000..2e1594b12ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_function.C
@@ -0,0 +1,58 @@
+// { 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)
+
+struct A
+{ void fn(); };
+
+template<typename>
+struct AHolder { };
+
+template<class T, class U>
+struct AHolder<U T::*>
+{ using type = U; };
+
+// Positive tests.
+SA(__is_function(int (int)));
+SA(__is_function(ClassType (ClassType)));
+SA(__is_function(float (int, float, int[], int&)));
+SA(__is_function(int (int, ...)));
+SA(__is_function(bool (ClassType) const));
+SA(__is_function(AHolder<decltype(&A::fn)>::type));
+
+void fn();
+SA(__is_function(decltype(fn)));
+
+// Negative tests.
+SA_TEST_CATEGORY(__is_function, int, false);
+SA_TEST_CATEGORY(__is_function, int*, false);
+SA_TEST_CATEGORY(__is_function, int&, false);
+SA_TEST_CATEGORY(__is_function, void, false);
+SA_TEST_CATEGORY(__is_function, void*, false);
+SA_TEST_CATEGORY(__is_function, void**, false);
+SA_TEST_CATEGORY(__is_function, std::nullptr_t, false);
+
+SA_TEST_CATEGORY(__is_function, AbstractClass, false);
+SA(!__is_function(int(&)(int)));
+SA(!__is_function(int(*)(int)));
+
+SA_TEST_CATEGORY(__is_function, A, false);
+SA_TEST_CATEGORY(__is_function, decltype(&A::fn), false);
+
+struct FnCallOverload
+{ void operator()(); };
+SA_TEST_CATEGORY(__is_function, FnCallOverload, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_function, ClassType, false);
+SA_TEST_CATEGORY(__is_function, IncompleteClass, false);
+SA_TEST_CATEGORY(__is_function, IncompleteUnion, false);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 19/23] libstdc++: Optimize std::is_function compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (17 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 18/23] c++: Implement __is_function built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 20/23] c++: Implement __is_object built-in trait Ken Matsui
                                               ` (3 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_function
by dispatching to the new __is_function built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_function): Use __is_function
	built-in trait.
	(is_function_v): Likewise. Optimize its implementation.  Move
	this under is_const_v as this depends on is_const_v.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index db880d87f60..b6d0441129b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -637,6 +637,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_function
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+  template<typename _Tp>
+    struct is_function
+    : public __bool_constant<__is_function(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_function
     : public __bool_constant<!is_const<const _Tp>::value> { };
@@ -648,6 +654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct is_function<_Tp&&>
     : public false_type { };
+#endif
 
 #ifdef __cpp_lib_is_null_pointer // C++ >= 11
   /// is_null_pointer (LWG 2247).
@@ -3255,8 +3262,7 @@ template <typename _Tp>
   inline constexpr bool is_union_v = __is_union(_Tp);
 template <typename _Tp>
   inline constexpr bool is_class_v = __is_class(_Tp);
-template <typename _Tp>
-  inline constexpr bool is_function_v = is_function<_Tp>::value;
+// is_function_v is defined below, after is_const_v.
 
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_reference)
 template <typename _Tp>
@@ -3293,6 +3299,19 @@ template <typename _Tp>
   inline constexpr bool is_const_v = false;
 template <typename _Tp>
   inline constexpr bool is_const_v<const _Tp> = true;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_function)
+template <typename _Tp>
+  inline constexpr bool is_function_v = __is_function(_Tp);
+#else
+template <typename _Tp>
+  inline constexpr bool is_function_v = !is_const_v<const _Tp>;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&> = false;
+template <typename _Tp>
+  inline constexpr bool is_function_v<_Tp&&> = false;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_volatile_v = false;
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 20/23] c++: Implement __is_object built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (18 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 19/23] libstdc++: Optimize std::is_function compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 21/23] libstdc++: Optimize std::is_object compilation performance Ken Matsui
                                               ` (2 subsequent siblings)
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::is_object.

gcc/cp/ChangeLog:

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

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __is_object.
	* g++.dg/ext/is_object.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/constraint.cc                     |  3 +++
 gcc/cp/cp-trait.def                      |  1 +
 gcc/cp/semantics.cc                      |  6 +++++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C |  3 +++
 gcc/testsuite/g++.dg/ext/is_object.C     | 29 ++++++++++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_object.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 4bea6089791..eeacead52a5 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3782,6 +3782,9 @@ diagnose_trait_expr (tree expr, tree args)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
 	  inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
+    case CPTK_IS_OBJECT:
+      inform (loc, "  %qT is not an object type", t1);
+      break;
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       inform (loc, "  %qT is not pointer-interconvertible base of %qT",
 	      t1, t2);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 89712f18667..b833efff26e 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -78,6 +78,7 @@ DEFTRAIT_EXPR (IS_MEMBER_POINTER, "__is_member_pointer", 1)
 DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2)
 DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1)
 DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2)
+DEFTRAIT_EXPR (IS_OBJECT, "__is_object", 1)
 DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2)
 DEFTRAIT_EXPR (IS_POD, "__is_pod", 1)
 DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 50330922d70..cf3d5476dbb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12415,6 +12415,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_NOTHROW_CONVERTIBLE:
       return is_nothrow_convertible (type1, type2);
 
+    case CPTK_IS_OBJECT:
+      return (type_code1 != FUNCTION_TYPE
+	      && type_code1 != REFERENCE_TYPE
+	      && type_code1 != VOID_TYPE);
+
     case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
       return pointer_interconvertible_base_of_p (type1, type2);
 
@@ -12615,6 +12620,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_MEMBER_FUNCTION_POINTER:
     case CPTK_IS_MEMBER_OBJECT_POINTER:
     case CPTK_IS_MEMBER_POINTER:
+    case CPTK_IS_OBJECT:
     case CPTK_IS_REFERENCE:
     case CPTK_IS_SAME:
     case CPTK_IS_SCOPED_ENUM:
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 5215da27d6f..2242276f633 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -113,6 +113,9 @@
 #if !__has_builtin (__is_nothrow_convertible)
 # error "__has_builtin (__is_nothrow_convertible) failed"
 #endif
+#if !__has_builtin (__is_object)
+# error "__has_builtin (__is_object) failed"
+#endif
 #if !__has_builtin (__is_pointer_interconvertible_base_of)
 # error "__has_builtin (__is_pointer_interconvertible_base_of) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/is_object.C b/gcc/testsuite/g++.dg/ext/is_object.C
new file mode 100644
index 00000000000..5c759a5ef69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_object.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+#define SA(X) static_assert((X),#X)
+
+#define SA_TEST_NON_VOLATILE(TRAIT, TYPE, EXPECT)	\
+  SA(TRAIT(TYPE) == EXPECT);				\
+  SA(TRAIT(const TYPE) == EXPECT)
+
+#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_NON_VOLATILE(__is_object, int (int), false);
+SA_TEST_NON_VOLATILE(__is_object, ClassType (ClassType), false);
+SA_TEST_NON_VOLATILE(__is_object,
+		     float (int, float, int[], int&), false);
+SA_TEST_CATEGORY(__is_object, int&, false);
+SA_TEST_CATEGORY(__is_object, ClassType&, false);
+SA_TEST_NON_VOLATILE(__is_object, int(&)(int), false);
+SA_TEST_CATEGORY(__is_object, void, false);
+
+// Sanity check.
+SA_TEST_CATEGORY(__is_object, ClassType, true);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 21/23] libstdc++: Optimize std::is_object compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (19 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 20/23] c++: Implement __is_object built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 22/23] c++: Implement __remove_pointer built-in trait Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 23/23] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::is_object
by dispatching to the new __is_object built-in trait.

libstdc++-v3/ChangeLog:
	* include/std/type_traits (is_object): Use __is_object built-in
	trait.
	(is_object_v): Likewise.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index b6d0441129b..2979d79a801 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -725,11 +725,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 
   /// is_object
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+  template<typename _Tp>
+    struct is_object
+    : public __bool_constant<__is_object(_Tp)>
+    { };
+#else
   template<typename _Tp>
     struct is_object
     : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                           is_void<_Tp>>>::type
     { };
+#endif
 
   template<typename>
     struct is_member_pointer;
@@ -3280,8 +3287,15 @@ template <typename _Tp>
   inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 template <typename _Tp>
   inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_object)
+template <typename _Tp>
+  inline constexpr bool is_object_v = __is_object(_Tp);
+#else
 template <typename _Tp>
   inline constexpr bool is_object_v = is_object<_Tp>::value;
+#endif
+
 template <typename _Tp>
   inline constexpr bool is_scalar_v = is_scalar<_Tp>::value;
 template <typename _Tp>
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 22/23] c++: Implement __remove_pointer built-in trait
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (20 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 21/23] libstdc++: Optimize std::is_object compilation performance Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  2023-12-07  5:33                             ` [PATCH v26 23/23] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch implements built-in trait for std::remove_pointer.

gcc/cp/ChangeLog:

	* cp-trait.def: Define __remove_pointer.
	* semantics.cc (finish_trait_type): Handle CPTK_REMOVE_POINTER.

gcc/testsuite/ChangeLog:

	* g++.dg/ext/has-builtin-1.C: Test existence of __remove_pointer.
	* g++.dg/ext/remove_pointer.C: New test.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/cp-trait.def                       |  1 +
 gcc/cp/semantics.cc                       |  5 +++
 gcc/testsuite/g++.dg/ext/has-builtin-1.C  |  3 ++
 gcc/testsuite/g++.dg/ext/remove_pointer.C | 51 +++++++++++++++++++++++
 4 files changed, 60 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/remove_pointer.C

diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index b833efff26e..394f006f20f 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -95,6 +95,7 @@ DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_tempo
 DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2)
 DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1)
 DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
+DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
 DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
 DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
 DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cf3d5476dbb..4b3acbcc767 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12695,6 +12695,11 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2,
 	type1 = TREE_TYPE (type1);
       return cv_unqualified (type1);
 
+    case CPTK_REMOVE_POINTER:
+      if (TYPE_PTR_P (type1))
+    type1 = TREE_TYPE (type1);
+      return type1;
+
     case CPTK_REMOVE_REFERENCE:
       if (TYPE_REF_P (type1))
 	type1 = TREE_TYPE (type1);
diff --git a/gcc/testsuite/g++.dg/ext/has-builtin-1.C b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
index 2242276f633..02b4b4d745d 100644
--- a/gcc/testsuite/g++.dg/ext/has-builtin-1.C
+++ b/gcc/testsuite/g++.dg/ext/has-builtin-1.C
@@ -167,6 +167,9 @@
 #if !__has_builtin (__remove_cvref)
 # error "__has_builtin (__remove_cvref) failed"
 #endif
+#if !__has_builtin (__remove_pointer)
+# error "__has_builtin (__remove_pointer) failed"
+#endif
 #if !__has_builtin (__remove_reference)
 # error "__has_builtin (__remove_reference) failed"
 #endif
diff --git a/gcc/testsuite/g++.dg/ext/remove_pointer.C b/gcc/testsuite/g++.dg/ext/remove_pointer.C
new file mode 100644
index 00000000000..7b13db93950
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/remove_pointer.C
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_same(__remove_pointer(int), int));
+SA(__is_same(__remove_pointer(int*), int));
+SA(__is_same(__remove_pointer(int**), int*));
+
+SA(__is_same(__remove_pointer(const int*), const int));
+SA(__is_same(__remove_pointer(const int**), const int*));
+SA(__is_same(__remove_pointer(int* const), int));
+SA(__is_same(__remove_pointer(int** const), int*));
+SA(__is_same(__remove_pointer(int* const* const), int* const));
+
+SA(__is_same(__remove_pointer(volatile int*), volatile int));
+SA(__is_same(__remove_pointer(volatile int**), volatile int*));
+SA(__is_same(__remove_pointer(int* volatile), int));
+SA(__is_same(__remove_pointer(int** volatile), int*));
+SA(__is_same(__remove_pointer(int* volatile* volatile), int* volatile));
+
+SA(__is_same(__remove_pointer(const volatile int*), const volatile int));
+SA(__is_same(__remove_pointer(const volatile int**), const volatile int*));
+SA(__is_same(__remove_pointer(const int* volatile), const int));
+SA(__is_same(__remove_pointer(volatile int* const), volatile int));
+SA(__is_same(__remove_pointer(int* const volatile), int));
+SA(__is_same(__remove_pointer(const int** volatile), const int*));
+SA(__is_same(__remove_pointer(volatile int** const), volatile int*));
+SA(__is_same(__remove_pointer(int** const volatile), int*));
+SA(__is_same(__remove_pointer(int* const* const volatile), int* const));
+SA(__is_same(__remove_pointer(int* volatile* const volatile), int* volatile));
+SA(__is_same(__remove_pointer(int* const volatile* const volatile), int* const volatile));
+
+SA(__is_same(__remove_pointer(int&), int&));
+SA(__is_same(__remove_pointer(const int&), const int&));
+SA(__is_same(__remove_pointer(volatile int&), volatile int&));
+SA(__is_same(__remove_pointer(const volatile int&), const volatile int&));
+
+SA(__is_same(__remove_pointer(int&&), int&&));
+SA(__is_same(__remove_pointer(const int&&), const int&&));
+SA(__is_same(__remove_pointer(volatile int&&), volatile int&&));
+SA(__is_same(__remove_pointer(const volatile int&&), const volatile int&&));
+
+SA(__is_same(__remove_pointer(int[3]), int[3]));
+SA(__is_same(__remove_pointer(const int[3]), const int[3]));
+SA(__is_same(__remove_pointer(volatile int[3]), volatile int[3]));
+SA(__is_same(__remove_pointer(const volatile int[3]), const volatile int[3]));
+
+SA(__is_same(__remove_pointer(int(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*volatile)(int)), int(int)));
+SA(__is_same(__remove_pointer(int(*const volatile)(int)), int(int)));
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* [PATCH v26 23/23] libstdc++: Optimize std::remove_pointer compilation performance
  2023-12-07  5:32                           ` Ken Matsui
                                               ` (21 preceding siblings ...)
  2023-12-07  5:33                             ` [PATCH v26 22/23] c++: Implement __remove_pointer built-in trait Ken Matsui
@ 2023-12-07  5:33                             ` Ken Matsui
  22 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: libstdc++, Ken Matsui

This patch optimizes the compilation performance of std::remove_pointer
by dispatching to the new remove_pointer built-in trait.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (remove_pointer): Use __remove_pointer
	built-in trait.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 libstdc++-v3/include/std/type_traits | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 2979d79a801..f00c07f94f9 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2089,6 +2089,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Pointer modifications.
 
+  /// remove_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__remove_pointer)
+  template<typename _Tp>
+    struct remove_pointer
+    { using type = __remove_pointer(_Tp); };
+#else
   template<typename _Tp, typename>
     struct __remove_pointer_helper
     { using type = _Tp; };
@@ -2097,11 +2103,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __remove_pointer_helper<_Tp, _Up*>
     { using type = _Up; };
 
-  /// remove_pointer
   template<typename _Tp>
     struct remove_pointer
     : public __remove_pointer_helper<_Tp, __remove_cv_t<_Tp>>
     { };
+#endif
 
   template<typename _Tp, typename = void>
     struct __add_pointer_helper
-- 
2.43.0


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-07  5:11                           ` [PATCH v26 00/23] " Ken Matsui
@ 2023-12-10 18:19                             ` Jason Merrill
  2023-12-11  2:25                               ` Ken Matsui
  2023-12-16 16:40                               ` Jonathan Wakely
  2023-12-20  3:22                             ` Sandra Loosemore
  1 sibling, 2 replies; 623+ messages in thread
From: Jason Merrill @ 2023-12-10 18:19 UTC (permalink / raw)
  To: Ken Matsui, gcc-patches; +Cc: libstdc++

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

On 12/7/23 00:11, Ken Matsui wrote:
> This patch series optimizes type traits compilation performance by
> implementing built-in type traits and using them in libstdc++.
> 
> Changes in v26:
> 
> 	* Rebased on top of trunk.
> 	* Moved is_function_v under is_const_v.
> 	* Isolated patches for is_const, is_volatile, is_pointer, and
> 	is_unbounded_array, which contain performance regression, from
> 	this patch series since they are not ready for review yet.

I've applied all the compiler patches, with a few small tweaks, 
including this one as a separate commit.  One other was a formatting 
fix, the lats was using TYPE_PTRDATAMEM_P for CPTK_IS_MEMBER_OBJECT_POINTER.

I'm leaving the library patches for library folks to apply.

Thanks!

Jason



[-- Attachment #2: 0001-c-trait-patch-tweak.patch --]
[-- Type: text/x-patch, Size: 1653 bytes --]

From e410303f768fa7b020e46f3bd7d28381144e5340 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Fri, 8 Dec 2023 15:55:49 -0500
Subject: [PATCH 01/11] c++: trait patch tweak
To: gcc-patches@gcc.gnu.org

As Patrick suggested elsewhere, let's move this into the default case.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_simple_type_specifier): Move trait
	handling to default label.
---
 gcc/cp/parser.cc | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9e76426566b..b987324f669 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -20164,22 +20164,22 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       return type;
 
     default:
+      /* If token is a type-yielding built-in traits, parse it.  */
+      const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer);
+      if (trait)
+	{
+	  type = cp_parser_trait (parser, trait);
+	  if (decl_specs)
+	    cp_parser_set_decl_spec_type (decl_specs, type,
+					  token,
+					  /*type_definition_p=*/false);
+
+	  return type;
+	}
+
       break;
     }
 
-  /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer);
-  if (trait)
-    {
-      type = cp_parser_trait (parser, trait);
-      if (decl_specs)
-	cp_parser_set_decl_spec_type (decl_specs, type,
-				      token,
-				      /*type_definition_p=*/false);
-
-      return type;
-    }
-
   /* If token is an already-parsed decltype not followed by ::,
      it's a simple-type-specifier.  */
   if (token->type == CPP_DECLTYPE
-- 
2.39.3


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-10 18:19                             ` Jason Merrill
@ 2023-12-11  2:25                               ` Ken Matsui
  2023-12-16 16:40                               ` Jonathan Wakely
  1 sibling, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-11  2:25 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Ken Matsui, gcc-patches, libstdc++

On Sun, Dec 10, 2023 at 10:19 AM Jason Merrill <jason@redhat.com> wrote:
>
> On 12/7/23 00:11, Ken Matsui wrote:
> > This patch series optimizes type traits compilation performance by
> > implementing built-in type traits and using them in libstdc++.
> >
> > Changes in v26:
> >
> >       * Rebased on top of trunk.
> >       * Moved is_function_v under is_const_v.
> >       * Isolated patches for is_const, is_volatile, is_pointer, and
> >       is_unbounded_array, which contain performance regression, from
> >       this patch series since they are not ready for review yet.
>
> I've applied all the compiler patches, with a few small tweaks,
> including this one as a separate commit.  One other was a formatting
> fix, the lats was using TYPE_PTRDATAMEM_P for CPTK_IS_MEMBER_OBJECT_POINTER.
>
> I'm leaving the library patches for library folks to apply.
>
> Thanks!
>

Thank you so much for your review and support!

> Jason
>
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-10 18:19                             ` Jason Merrill
  2023-12-11  2:25                               ` Ken Matsui
@ 2023-12-16 16:40                               ` Jonathan Wakely
  2023-12-16 16:56                                 ` Ken Matsui
  1 sibling, 1 reply; 623+ messages in thread
From: Jonathan Wakely @ 2023-12-16 16:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Ken Matsui, gcc-patches, libstdc++

On Sun, 10 Dec 2023 at 18:19, Jason Merrill wrote:
>
> On 12/7/23 00:11, Ken Matsui wrote:
> > This patch series optimizes type traits compilation performance by
> > implementing built-in type traits and using them in libstdc++.
> >
> > Changes in v26:
> >
> >       * Rebased on top of trunk.
> >       * Moved is_function_v under is_const_v.
> >       * Isolated patches for is_const, is_volatile, is_pointer, and
> >       is_unbounded_array, which contain performance regression, from
> >       this patch series since they are not ready for review yet.
>
> I've applied all the compiler patches, with a few small tweaks,
> including this one as a separate commit.  One other was a formatting
> fix, the lats was using TYPE_PTRDATAMEM_P for CPTK_IS_MEMBER_OBJECT_POINTER.
>
> I'm leaving the library patches for library folks to apply.

I've reviewed all the library patches in v26 and they are all OK for
trunk. Please push (or Patrick can do so).

Thanks, Ken! Great work, I'm really happy to see this land in GCC trunk.

+Reviewed-by: Jonathan Wakely <jwakely@redhat.com>


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-16 16:40                               ` Jonathan Wakely
@ 2023-12-16 16:56                                 ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-16 16:56 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jason Merrill, Ken Matsui, gcc-patches, libstdc++

On Sat, Dec 16, 2023 at 8:40 AM Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On Sun, 10 Dec 2023 at 18:19, Jason Merrill wrote:
> >
> > On 12/7/23 00:11, Ken Matsui wrote:
> > > This patch series optimizes type traits compilation performance by
> > > implementing built-in type traits and using them in libstdc++.
> > >
> > > Changes in v26:
> > >
> > >       * Rebased on top of trunk.
> > >       * Moved is_function_v under is_const_v.
> > >       * Isolated patches for is_const, is_volatile, is_pointer, and
> > >       is_unbounded_array, which contain performance regression, from
> > >       this patch series since they are not ready for review yet.
> >
> > I've applied all the compiler patches, with a few small tweaks,
> > including this one as a separate commit.  One other was a formatting
> > fix, the lats was using TYPE_PTRDATAMEM_P for CPTK_IS_MEMBER_OBJECT_POINTER.
> >
> > I'm leaving the library patches for library folks to apply.
>
> I've reviewed all the library patches in v26 and they are all OK for
> trunk. Please push (or Patrick can do so).
>
> Thanks, Ken! Great work, I'm really happy to see this land in GCC trunk.
>
> +Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
>

Thank you so much for taking the time to review my patches and for
your kind support!  I will push :)

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-07  5:11                           ` [PATCH v26 00/23] " Ken Matsui
  2023-12-10 18:19                             ` Jason Merrill
@ 2023-12-20  3:22                             ` Sandra Loosemore
  2023-12-20 15:55                               ` Patrick Palka
  1 sibling, 1 reply; 623+ messages in thread
From: Sandra Loosemore @ 2023-12-20  3:22 UTC (permalink / raw)
  To: Ken Matsui, gcc-patches; +Cc: libstdc++

On 12/6/23 22:11, Ken Matsui wrote:
> This patch series optimizes type traits compilation performance by
> implementing built-in type traits and using them in libstdc++.

I'm finding that all the new g++.dg/ext/is_*.C testcases added by this patch 
series are failing due
to the "#include <testsuite_tr1.h>".  If that is supposed to refer to the file 
of that name in the libstdc++ testcase, there's no gcc option being passed to 
add that location to the include search path.  That .h file includes other 
header files from the libstdc++ testsuite so just copying it into the same 
directory as the new g++ tests doesn't work.  Can you fix this, somehow?

Target is nios2-elf, if that matters.

-Sandra

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-20  3:22                             ` Sandra Loosemore
@ 2023-12-20 15:55                               ` Patrick Palka
  2023-12-20 17:13                                 ` Ken Matsui
  0 siblings, 1 reply; 623+ messages in thread
From: Patrick Palka @ 2023-12-20 15:55 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: Ken Matsui, gcc-patches, libstdc++

On Tue, 19 Dec 2023, Sandra Loosemore wrote:

> On 12/6/23 22:11, Ken Matsui wrote:
> > This patch series optimizes type traits compilation performance by
> > implementing built-in type traits and using them in libstdc++.
> 
> I'm finding that all the new g++.dg/ext/is_*.C testcases added by this patch
> series are failing due
> to the "#include <testsuite_tr1.h>".  If that is supposed to refer to the file
> of that name in the libstdc++ testcase, there's no gcc option being passed to
> add that location to the include search path.  That .h file includes other
> header files from the libstdc++ testsuite so just copying it into the same
> directory as the new g++ tests doesn't work.  Can you fix this, somehow?

Looks like the testcases only use the trivial definition of
__gnu_test::ClassType from the header, so perhaps we can just define it
locally and remove this header include (which IIUC is intended to be
used for library tests run by the libstdc++ test harness, not front-end
tests).

Ken, do you want to submit a patch for that?  (A full bootstrap +
regtest wouldn't be necessary, it should suffice to re-run the changed
tests via e.g. make check RUNTESTFLAGS="dg.exp=*ext*")

> 
> Target is nios2-elf, if that matters.
> 
> -Sandra
> 
> 


^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v26 00/23] Optimize type traits compilation performance
  2023-12-20 15:55                               ` Patrick Palka
@ 2023-12-20 17:13                                 ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2023-12-20 17:13 UTC (permalink / raw)
  To: Patrick Palka; +Cc: Sandra Loosemore, Ken Matsui, gcc-patches, libstdc++

On Wed, Dec 20, 2023 at 7:56 AM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Tue, 19 Dec 2023, Sandra Loosemore wrote:
>
> > On 12/6/23 22:11, Ken Matsui wrote:
> > > This patch series optimizes type traits compilation performance by
> > > implementing built-in type traits and using them in libstdc++.
> >
> > I'm finding that all the new g++.dg/ext/is_*.C testcases added by this patch
> > series are failing due
> > to the "#include <testsuite_tr1.h>".  If that is supposed to refer to the file
> > of that name in the libstdc++ testcase, there's no gcc option being passed to
> > add that location to the include search path.  That .h file includes other
> > header files from the libstdc++ testsuite so just copying it into the same
> > directory as the new g++ tests doesn't work.  Can you fix this, somehow?
>
> Looks like the testcases only use the trivial definition of
> __gnu_test::ClassType from the header, so perhaps we can just define it
> locally and remove this header include (which IIUC is intended to be
> used for library tests run by the libstdc++ test harness, not front-end
> tests).
>
> Ken, do you want to submit a patch for that?  (A full bootstrap +
> regtest wouldn't be necessary, it should suffice to re-run the changed
> tests via e.g. make check RUNTESTFLAGS="dg.exp=*ext*")
>

Sure!  Let me fix this problem :)

> >
> > Target is nios2-elf, if that matters.
> >
> > -Sandra
> >
> >
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

* Re: [PATCH v23 32/33] c++: Implement __is_invocable built-in trait
  2023-10-23 21:23                               ` Jason Merrill
@ 2024-02-20  1:35                                 ` Ken Matsui
  0 siblings, 0 replies; 623+ messages in thread
From: Ken Matsui @ 2024-02-20  1:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Ken Matsui, gcc-patches, libstdc++, Patrick Palka

On Mon, Oct 23, 2023 at 2:23 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 10/20/23 17:37, Patrick Palka wrote:
> > On Fri, 20 Oct 2023, Patrick Palka wrote:
> >
> >> On Fri, 20 Oct 2023, Patrick Palka wrote:
> >>
> >>> On Fri, 20 Oct 2023, Ken Matsui wrote:
> >>>
> >>>> This patch implements built-in trait for std::is_invocable.
> >>>
> >>> Nice!  My email client unfortunately ate my first review attempt, so
> >>> apologies for my brevity this time around.
> >>>
> >>>> gcc/cp/ChangeLog:
> >>>>
> >>>>    * cp-trait.def: Define __is_invocable.
> >>>>    * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_INVOCABLE.
> >>>>    * semantics.cc (trait_expr_value): Likewise.
> >>>>    (finish_trait_expr): Likewise.
> >>>>    (is_invocable_p): New function.
> >>>>    * method.h: New file to export build_trait_object in method.cc.
>
> Given how much larger semantics.cc is than method.cc, maybe let's put
> is_invocable_p in method.cc instead?  And in general declarations can go
> in cp-tree.h.
>
> >>>> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> >>>> index 7cccbae5287..cc2e400531a 100644
> >>>> --- a/gcc/cp/semantics.cc
> >>>> +++ b/gcc/cp/semantics.cc
> >>>> @@ -45,6 +45,10 @@ along with GCC; see the file COPYING3.  If not see
> >>>>   #include "gomp-constants.h"
> >>>>   #include "predict.h"
> >>>>   #include "memmodel.h"
> >>>> +#include "method.h"
> >>>> +
> >>>> +#include "print-tree.h"
> >>>> +#include "tree-pretty-print.h"
> >>>>
> >>>>   /* There routines provide a modular interface to perform many parsing
> >>>>      operations.  They may therefore be used during actual parsing, or
> >>>> @@ -11714,6 +11718,133 @@ classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
> >>>>     return saw_copy;
> >>>>   }
> >>>>
> >>>> +/* Return true if FN_TYPE is invocable with the given ARG_TYPES.  */
> >>>> +
> >>>> +static bool
> >>>> +is_invocable_p (tree fn_type, tree arg_types)
> >
> > (Sorry for the spam)  We'll eventually want to implement a built-in for
> > invoke_result, so perhaps we should preemptively factor out the bulk
> > of this function into a 'build_INVOKE' helper function that returns the
> > built tree?
> >
> >>>> +{
> >>>> +  /* ARG_TYPES must be a TREE_VEC.  */
> >>>> +  gcc_assert (TREE_CODE (arg_types) == TREE_VEC);
> >>>> +
> >>>> +  /* Access check is required to determine if the given is invocable.  */
> >>>> +  deferring_access_check_sentinel acs (dk_no_deferred);
> >>>> +
> >>>> +  /* std::is_invocable is an unevaluated context.  */
> >>>> +  cp_unevaluated cp_uneval_guard;
> >>>> +
> >>>> +  bool is_ptrdatamem;
> >>>> +  bool is_ptrmemfunc;
> >>>> +  if (TREE_CODE (fn_type) == REFERENCE_TYPE)
> >>>> +    {
> >>>> +      tree deref_fn_type = TREE_TYPE (fn_type);
> >>>> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (deref_fn_type);
> >>>> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (deref_fn_type);
> >>>> +
> >>>> +      /* Dereference fn_type if it is a pointer to member.  */
> >>>> +      if (is_ptrdatamem || is_ptrmemfunc)
> >>>> +  fn_type = deref_fn_type;
> >>>> +    }
> >>>> +  else
> >>>> +    {
> >>>> +      is_ptrdatamem = TYPE_PTRDATAMEM_P (fn_type);
> >>>> +      is_ptrmemfunc = TYPE_PTRMEMFUNC_P (fn_type);
> >>>> +    }
> >>>> +
> >>>> +  if (is_ptrdatamem && TREE_VEC_LENGTH (arg_types) != 1)
> >>>> +    /* A pointer to data member with non-one argument is not invocable.  */
> >>>> +    return false;
> >>>> +
> >>>> +  if (is_ptrmemfunc && TREE_VEC_LENGTH (arg_types) == 0)
> >>>> +    /* A pointer to member function with no arguments is not invocable.  */
> >>>> +    return false;
> >>>> +
> >>>> +  /* Construct an expression of a pointer to member.  */
> >>>> +  tree datum;
> >>>> +  if (is_ptrdatamem || is_ptrmemfunc)
> >>>> +    {
> >>>> +      tree datum_type = TREE_VEC_ELT (arg_types, 0);
> >>>> +
> >>>> +      /* Dereference datum.  */
> >>>> +      if (CLASS_TYPE_P (datum_type))
> >>>> +  {
> >>>> +    bool is_refwrap = false;
> >>>> +
> >>>> +    tree datum_decl = TYPE_NAME (TYPE_MAIN_VARIANT (datum_type));
> >>>> +    if (decl_in_std_namespace_p (datum_decl))
> >>>> +      {
> >>>> +        tree name = DECL_NAME (datum_decl);
> >>>> +        if (name && (id_equal (name, "reference_wrapper")))
> >>>> +          {
> >>>> +            /* Handle std::reference_wrapper.  */
> >>>> +            is_refwrap = true;
> >>>> +            datum_type = cp_build_reference_type (datum_type, false);
>
> Why do you change datum_type from std::reference_wrapper<...> to
> std::reference_wrapper<...>&?
>
> >>>> +          }
> >>>> +      }
> >>>> +
> >>>> +    datum = build_trait_object (datum_type);
> >>>> +
> >>>> +    /* If datum_type was not std::reference_wrapper, check if it has
> >>>> +       operator*() overload.  If datum_type was std::reference_wrapper,
> >>>> +       avoid dereferencing the datum twice.  */
> >>>> +    if (!is_refwrap)
> >>>> +      if (get_class_binding (datum_type, get_identifier ("operator*")))
> >>>
> >>> We probably should use lookup_member instead of get_class_binding since
> >>> IIUC the latter doesn't look into bases:
> >>>
> >>>    struct A { int m; };
> >>>    struct B { A& operator*(): };
> >>>    struct C : B { };
> >>>    static_assert(std::is_invocable_v<int A::*, C>);
> >>>
> >>> However, I notice that the specification of INVOKE
> >>> (https://eel.is/c++draft/func.require#lib:INVOKE) doesn't mention name
> >>> lookup at all so it strikes me as suspicious that we'd perform name
> >>> lookup here.
>
> Agreed.  It seems that whether or not to build_x_indirect_ref should
> depend instead on whether f is a pointer to a member of decltype(t1) (as
> well as is_refwrap).
>
> >>>  I think this would misbehave for:
> >>>
> >>>    struct A { };
> >>>    struct B : A { A& operator*() = delete; };
> >>>    static_assert(std::is_invocable_v<int A::*, B>);
> >>>
> >>>    struct C : private A { A& operator*(); };
> >>>    static_assert(std::is_invocable_v<int A::*, C>);
> >>
> >> Oops, this static_assert is missing a !
> >>
> >>>
> >>> ultimately because we end up choosing the dereference form of INVOKE,
> >>> but according to 1.1/1.4 we should choose the non-dereference form?
> >>>
> >>>> +        /* Handle operator*().  */
> >>>> +        datum = build_x_indirect_ref (UNKNOWN_LOCATION, datum,
> >>>> +                                      RO_UNARY_STAR, NULL_TREE,
> >>>> +                                      tf_none);
> >>>> +  }
> >>>> +      else if (POINTER_TYPE_P (datum_type))
> >>>> +  datum = build_trait_object (TREE_TYPE (datum_type));
> >>>> +      else
> >>>> +  datum = build_trait_object (datum_type);
> >>>> +    }
> >>>> +
> >>>> +  /* Build a function expression.  */
> >>>> +  tree fn;
> >>>> +  if (is_ptrdatamem)
> >>>> +    fn = build_m_component_ref (datum, build_trait_object (fn_type), tf_none);
> >>>
> >>> Maybe exit early for the is_ptrdatamem case here (and simplify the rest
> >>> of the function accordingly)?
> >>>
> >>>> +  else if (is_ptrmemfunc)
> >>>> +    fn = build_trait_object (TYPE_PTRMEMFUNC_FN_TYPE (fn_type));
>
> Why not use build_m_component_ref and build_offset_ref_call_from_tree
> like it would if you wrote (t1.*f)() directly?
>

Thank you so much for your review!  I will apply your suggestions.

> Jason
>

^ permalink raw reply	[flat|nested] 623+ messages in thread

end of thread, other threads:[~2024-02-20  1:35 UTC | newest]

Thread overview: 623+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-14  6:42 [PATCH v11 00/40] Optimize type traits performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-09-14  6:42 ` [PATCH v11 02/40] c++: Implement __is_const built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 06/40] c++: Implement __is_array built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
2023-09-14 17:53   ` Joseph Myers
2023-09-14 21:44     ` Ken Matsui
2023-09-15 23:26     ` Ken Matsui
2023-09-14  6:42 ` [PATCH v11 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
2023-09-14  6:42 ` [PATCH v11 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-09-14  6:42 ` [PATCH v11 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-09-14  6:42 ` [PATCH v11 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-09-14  6:43 ` [PATCH v11 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-09-14  6:43 ` [PATCH v11 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-09-14  6:43 ` [PATCH v11 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-09-14  6:43 ` [PATCH v11 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-09-14  6:43 ` [PATCH v11 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-09-15  2:21 ` [PATCH v12 00/40] Optimize type traits performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-09-15  2:21   ` [PATCH v12 02/40] c++: Implement __is_const built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 06/40] c++: Implement __is_array built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
2023-09-15  2:21   ` [PATCH v12 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
2023-09-15  2:21   ` [PATCH v12 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-09-15  2:21   ` [PATCH v12 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-09-15  2:21   ` [PATCH v12 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-09-15  2:21   ` [PATCH v12 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-09-15  2:21   ` [PATCH v12 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-09-15  2:21   ` [PATCH v12 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-09-15  2:34   ` [PATCH v13 00/40] Optimize type traits performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-09-15  2:34     ` [PATCH v13 02/40] c++: Implement __is_const built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 06/40] c++: Implement __is_array built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
2023-09-15 23:50       ` [PATCH v14 00/40] Optimize type traits performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 01/40] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-09-15 23:50         ` [PATCH v14 02/40] c++: Implement __is_const built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 03/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 04/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 05/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 06/40] c++: Implement __is_array built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 07/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 08/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 09/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 10/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 11/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-09-15 23:50         ` [PATCH v14 12/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-09-15 23:50         ` [PATCH v14 13/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 14/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 15/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 16/40] c, c++: Use 16 bits for all use of enum rid for more keyword space Ken Matsui
2023-09-19 16:58           ` Jason Merrill
2023-09-19 23:05             ` Ken Matsui
2023-09-27 13:57               ` Jason Merrill
2023-10-09  5:03                 ` Ken Matsui
2023-09-15 23:51         ` [PATCH v14 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
2023-09-15 23:51         ` [PATCH v14 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-09-15 23:51         ` [PATCH v14 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-09-15 23:51         ` [PATCH v14 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-09-15 23:51         ` [PATCH v14 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-09-15 23:51         ` [PATCH v14 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-09-15 23:51         ` [PATCH v14 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-09-15  2:34     ` [PATCH v13 17/40] c-family: Fix C_SET_RID_CODE to handle 16-bit rid code correctly Ken Matsui
2023-09-15  2:34     ` [PATCH v13 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-09-15  2:34     ` [PATCH v13 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-09-15  2:35     ` [PATCH v13 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 29/40] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 31/40] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-09-15  2:35     ` [PATCH v13 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-09-15  2:35     ` [PATCH v13 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 37/40] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-09-15  2:35     ` [PATCH v13 39/40] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-09-15  2:35     ` [PATCH v13 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-10  9:46     ` [PATCH v15 00/39] Optimize type traits performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-10-10  9:46       ` [PATCH v15 02/39] c-family, c++: Look up traits through gperf instead of enum rid Ken Matsui
2023-10-10  9:46       ` [PATCH v15 03/39] c++: Implement __is_const built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 07/39] c++: Implement __is_array built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 21/39] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 23/39] c++: Implement __is_function built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 25/39] libstdc++: Optimize is_object " Ken Matsui
2023-10-10  9:46       ` [PATCH v15 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-10  9:46       ` [PATCH v15 33/39] libstdc++: Optimize is_compound " Ken Matsui
2023-10-10  9:46       ` [PATCH v15 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-10  9:46       ` [PATCH v15 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-10-10  9:46       ` [PATCH v15 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-10 22:09       ` [PATCH v16 00/39] Optimize type traits performance Ken Matsui
2023-10-10 22:09         ` [PATCH v16 01/39] c++: Sort built-in identifiers alphabetically Ken Matsui
2023-10-10 22:09         ` [PATCH v16 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
2023-10-11 20:09           ` Patrick Palka
2023-10-11 21:34             ` Ken Matsui
2023-10-10 22:09         ` [PATCH v16 03/39] c++: Implement __is_const built-in trait Ken Matsui
2023-10-10 22:09         ` [PATCH v16 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-10 22:09         ` [PATCH v16 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-10 22:09         ` [PATCH v16 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-10 22:09         ` [PATCH v16 07/39] c++: Implement __is_array built-in trait Ken Matsui
2023-10-10 22:09         ` [PATCH v16 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 21/39] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 23/39] c++: Implement __is_function built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 25/39] libstdc++: Optimize is_object " Ken Matsui
2023-10-10 22:10         ` [PATCH v16 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-10 22:10         ` [PATCH v16 33/39] libstdc++: Optimize is_compound " Ken Matsui
2023-10-10 22:10         ` [PATCH v16 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-10 22:10         ` [PATCH v16 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-10-10 22:10         ` [PATCH v16 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-11 21:45         ` [PATCH v17 00/39] Optimize type traits performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 01/39] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-11 21:45           ` [PATCH v17 02/39] c-family, c++: Look up built-in traits through gperf Ken Matsui
2023-10-12 17:02             ` Patrick Palka
2023-10-11 21:45           ` [PATCH v17 03/39] c++: Implement __is_const built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 04/39] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 05/39] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 06/39] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 07/39] c++: Implement __is_array built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 08/39] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 09/39] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 10/39] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 11/39] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 12/39] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 13/39] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 14/39] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 15/39] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 16/39] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 17/39] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 18/39] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 19/39] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 20/39] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 21/39] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-11 21:45           ` [PATCH v17 22/39] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-11 21:45           ` [PATCH v17 23/39] c++: Implement __is_function built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 24/39] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 25/39] libstdc++: Optimize is_object " Ken Matsui
2023-10-11 21:46           ` [PATCH v17 26/39] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 27/39] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 28/39] c++, libstdc++: Implement __is_pointer built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 29/39] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 30/39] c++, libstdc++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 31/39] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 32/39] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-11 21:46           ` [PATCH v17 33/39] libstdc++: Optimize is_compound " Ken Matsui
2023-10-11 21:46           ` [PATCH v17 34/39] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 35/39] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 36/39] c++, libstdc++: Implement __is_signed built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 37/39] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-11 21:46           ` [PATCH v17 38/39] c++, libstdc++: Implement __is_scalar built-in trait Ken Matsui
2023-10-11 21:46           ` [PATCH v17 39/39] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-13 21:03           ` [PATCH v18 00/40] Optimize type traits performance Ken Matsui
2023-10-13 21:03             ` [PATCH v18 01/40] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-13 21:03             ` [PATCH v18 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
2023-10-13 21:03             ` [PATCH v18 03/40] c++: Accept the use of non-function-like built-in trait identifiers Ken Matsui
2023-10-13 21:04             ` [PATCH v18 04/40] c++: Implement __is_const built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 08/40] c++: Implement __is_array built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-10-13 21:04             ` [PATCH v18 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-13 21:04             ` [PATCH v18 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-10-13 21:04             ` [PATCH v18 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 37/40] c++: Implement __is_signed built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-13 21:04             ` [PATCH v18 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
2023-10-13 21:04             ` [PATCH v18 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-13 22:37             ` [PATCH v19 00/40] Optimize type traits performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 01/40] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-13 22:37               ` [PATCH v19 02/40] c-family, c++: Look up built-in traits through gperf Ken Matsui
2023-10-15 20:43                 ` Patrick Palka
2023-10-15 21:04                   ` Ken Matsui
2023-10-15 21:50                     ` Patrick Palka
2023-10-15 21:52                       ` Ken Matsui
2023-10-13 22:37               ` [PATCH v19 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-13 22:37               ` [PATCH v19 04/40] c++: Implement __is_const built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 08/40] c++: Implement __is_array built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-10-13 22:37               ` [PATCH v19 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-13 22:37               ` [PATCH v19 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-10-13 22:37               ` [PATCH v19 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 37/40] c++: Implement __is_signed built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-13 22:37               ` [PATCH v19 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
2023-10-13 22:37               ` [PATCH v19 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-16  0:09               ` [PATCH v20 00/40] Optimize type traits performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 01/40] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-16 15:16                   ` Patrick Palka
2023-10-16 20:11                     ` Ken Matsui
2023-10-16 21:12                       ` Patrick Palka
2023-10-16 21:30                         ` Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 02/40] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-10-16 14:55                   ` Patrick Palka
2023-10-16 19:57                     ` Ken Matsui
2023-10-16 21:06                       ` Patrick Palka
2023-10-16 21:27                         ` Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 03/40] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-16 15:00                   ` Patrick Palka
2023-10-16  0:09                 ` [PATCH v20 04/40] c++: Implement __is_const built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 05/40] libstdc++: Optimize is_const trait performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 06/40] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 07/40] libstdc++: Optimize is_volatile trait performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 08/40] c++: Implement __is_array built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 09/40] libstdc++: Optimize is_array trait performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 10/40] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 11/40] libstdc++: Optimize is_unbounded_array trait performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 12/40] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 13/40] libstdc++: Optimize is_bounded_array trait performance Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 14/40] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-16  0:09                 ` [PATCH v20 15/40] libstdc++: Optimize is_scoped_enum trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 16/40] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 17/40] libstdc++: Optimize is_member_pointer trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 18/40] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 19/40] libstdc++: Optimize is_member_function_pointer trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 20/40] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 21/40] libstdc++: Optimize is_member_object_pointer trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 22/40] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 23/40] libstdc++: Optimize is_reference trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 24/40] c++: Implement __is_function built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 25/40] libstdc++: Optimize is_function trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 26/40] libstdc++: Optimize is_object " Ken Matsui
2023-10-16 18:04                   ` Patrick Palka
2023-10-16 20:26                     ` Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 27/40] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 28/40] libstdc++: Optimize remove_pointer trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 29/40] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 30/40] libstdc++: Optimize is_pointer trait performance Ken Matsui
2023-10-16 16:36                   ` Patrick Palka
2023-10-16 20:22                     ` Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 31/40] c++: Implement __is_arithmetic built-in trait Ken Matsui
2023-10-16 17:16                   ` Patrick Palka
2023-10-16 20:25                     ` Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 32/40] libstdc++: Optimize is_arithmetic trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 33/40] libstdc++: Optimize is_fundamental " Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 34/40] libstdc++: Optimize is_compound " Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 35/40] c++: Implement __is_unsigned built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 36/40] libstdc++: Optimize is_unsigned trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 37/40] c++: Implement __is_signed built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 38/40] libstdc++: Optimize is_signed trait performance Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 39/40] c++: Implement __is_scalar built-in trait Ken Matsui
2023-10-16  0:10                 ` [PATCH v20 40/40] libstdc++: Optimize is_scalar trait performance Ken Matsui
2023-10-17 11:27                 ` [PATCH v21 00/30] Optimize type traits performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 01/30] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 02/30] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 03/30] c++: Implement __is_const built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 04/30] libstdc++: Optimize std::is_const compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 05/30] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 06/30] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 07/30] c++: Implement __is_array built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 08/30] libstdc++: Optimize std::is_array compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 09/30] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 10/30] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 11/30] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 12/30] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 13/30] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 14/30] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 15/30] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 16/30] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 17/30] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 18/30] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 19/30] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 20/30] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 21/30] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 22/30] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 23/30] c++: Implement __is_function built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 24/30] libstdc++: Optimize std::is_function compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 25/30] c++: Implement __is_object built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 26/30] libstdc++: Optimize std::is_object compilation performance Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 27/30] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-17 11:27                   ` [PATCH v21 28/30] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
2023-10-17 11:28                   ` [PATCH v21 29/30] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-17 11:28                   ` [PATCH v21 30/30] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
2023-10-17 11:36                   ` [PATCH v22 00/31] Optimize type traits performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 01/31] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 02/31] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-10-17 17:04                       ` Patrick Palka
2023-10-17 11:36                     ` [PATCH v22 03/31] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 04/31] c++: Implement __is_const built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 05/31] libstdc++: Optimize std::is_const compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 06/31] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 07/31] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 08/31] c++: Implement __is_array built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 09/31] libstdc++: Optimize std::is_array compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 10/31] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 11/31] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 12/31] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 13/31] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 14/31] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 15/31] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 16/31] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 17/31] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 18/31] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 19/31] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 20/31] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 21/31] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 22/31] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 23/31] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 24/31] c++: Implement __is_function built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 25/31] libstdc++: Optimize std::is_function compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 26/31] c++: Implement __is_object built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 27/31] libstdc++: Optimize std::is_object compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 28/31] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 29/31] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 30/31] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-17 11:36                     ` [PATCH v22 31/31] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
2023-10-20 13:53                     ` [PATCH v23 00/33] Optimize type traits performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 01/33] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-10-20 19:11                         ` Patrick Palka
2023-10-20 20:00                           ` Ken Matsui
2023-10-23 20:27                         ` Jason Merrill
2023-10-23 21:08                           ` Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-23 20:36                         ` Jason Merrill
2023-10-23 21:08                           ` Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 04/33] c++: Implement __is_const built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 08/33] c++: Implement __is_array built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 22/33] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 24/33] c++: Implement __is_function built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 26/33] c++: Implement __is_object built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
2023-10-22 12:06                         ` Ken Matsui
2023-10-23 17:00                           ` Patrick Palka
2023-10-23 17:12                             ` Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
2023-10-20 21:29                         ` Patrick Palka
2023-10-20 21:31                           ` Patrick Palka
2023-10-20 21:37                             ` Patrick Palka
2023-10-23 21:23                               ` Jason Merrill
2024-02-20  1:35                                 ` Ken Matsui
2023-10-20 13:53                       ` [PATCH v23 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
2023-10-20 16:16                       ` [PATCH v24 00/33] Optimize type traits performance Ken Matsui
2023-10-20 16:17                         ` [PATCH v24 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
2023-10-23 17:04                           ` Patrick Palka
2023-10-23 17:14                             ` Ken Matsui
2023-10-23 17:38                               ` Patrick Palka
2023-10-23 17:47                                 ` Ken Matsui
2023-10-24  2:00                         ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 01/33] c++: Sort built-in traits alphabetically Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 02/33] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 03/33] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 04/33] c++: Implement __is_const built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 05/33] libstdc++: Optimize std::is_const compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 06/33] c++: Implement __is_volatile built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 07/33] libstdc++: Optimize std::is_volatile compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 08/33] c++: Implement __is_array built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 09/33] libstdc++: Optimize std::is_array compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 10/33] c++: Implement __is_unbounded_array built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 11/33] libstdc++: Optimize std::is_unbounded_array compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 12/33] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 13/33] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 14/33] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 15/33] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
2023-10-24  2:00                           ` [PATCH v25 16/33] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 17/33] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 18/33] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 19/33] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 20/33] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 21/33] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 22/33] c++: Implement __is_reference built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 23/33] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 24/33] c++: Implement __is_function built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 25/33] libstdc++: Optimize std::is_function compilation performance Ken Matsui
2023-10-24 11:01                             ` Jonathan Wakely
2023-12-07  3:20                               ` Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 26/33] c++: Implement __is_object built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 27/33] libstdc++: Optimize std::is_object compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 28/33] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 29/33] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 30/33] c++: Implement __is_pointer built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 31/33] libstdc++: Optimize std::is_pointer compilation performance Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 32/33] c++: Implement __is_invocable built-in trait Ken Matsui
2023-10-24  2:01                           ` [PATCH v25 33/33] libstdc++: Optimize std::is_invocable compilation performance Ken Matsui
2023-10-24  2:07                           ` [PATCH v25 00/33] Optimize type traits " Ken Matsui
2023-12-07  5:11                           ` [PATCH v26 00/23] " Ken Matsui
2023-12-10 18:19                             ` Jason Merrill
2023-12-11  2:25                               ` Ken Matsui
2023-12-16 16:40                               ` Jonathan Wakely
2023-12-16 16:56                                 ` Ken Matsui
2023-12-20  3:22                             ` Sandra Loosemore
2023-12-20 15:55                               ` Patrick Palka
2023-12-20 17:13                                 ` Ken Matsui
2023-12-07  5:32                           ` Ken Matsui
2023-12-07  5:32                             ` [PATCH v26 01/23] c++: Sort built-in traits alphabetically Ken Matsui
2023-12-07  5:32                             ` [PATCH v26 02/23] c-family, c++: Look up built-in traits via identifier node Ken Matsui
2023-12-07  5:32                             ` [PATCH v26 03/23] c++: Accept the use of built-in trait identifiers Ken Matsui
2023-12-07  5:32                             ` [PATCH v26 04/23] c++: Implement __is_array built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 05/23] libstdc++: Optimize std::is_array compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 06/23] c++: Implement __is_bounded_array built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 07/23] libstdc++: Optimize std::is_bounded_array compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 08/23] c++: Implement __is_scoped_enum built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 09/23] libstdc++: Optimize std::is_scoped_enum compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 10/23] c++: Implement __is_member_pointer built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 11/23] libstdc++: Optimize std::is_member_pointer compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 12/23] c++: Implement __is_member_function_pointer built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 13/23] libstdc++: Optimize std::is_member_function_pointer compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 14/23] c++: Implement __is_member_object_pointer built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 15/23] libstdc++: Optimize std::is_member_object_pointer compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 16/23] c++: Implement __is_reference built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 17/23] libstdc++: Optimize std::is_reference compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 18/23] c++: Implement __is_function built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 19/23] libstdc++: Optimize std::is_function compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 20/23] c++: Implement __is_object built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 21/23] libstdc++: Optimize std::is_object compilation performance Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 22/23] c++: Implement __remove_pointer built-in trait Ken Matsui
2023-12-07  5:33                             ` [PATCH v26 23/23] libstdc++: Optimize std::remove_pointer compilation performance Ken Matsui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).