diff mbox series

[v16,02/39] c-family, c++: Look up built-in traits through gperf

Message ID 20231010221520.3680267-3-kmatsui@gcc.gnu.org
State New
Headers show
Series Optimize type traits performance | expand

Commit Message

Ken Matsui Oct. 10, 2023, 10:09 p.m. UTC
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

Comments

Patrick Palka Oct. 11, 2023, 8:09 p.m. UTC | #1
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"
>  
>  
>  /* 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
> 
>
Ken Matsui Oct. 11, 2023, 9:34 p.m. UTC | #2
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
> >
> >
>
diff mbox series

Patch

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,