[v23,02/33] c-family, c++: Look up built-in traits via identifier node

Message ID 20231020135748.1846670-3-kmatsui@gcc.gnu.org
State Accepted
Headers
Series Optimize type traits performance |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Ken Matsui Oct. 20, 2023, 1:53 p.m. UTC
  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(-)
  

Comments

Patrick Palka Oct. 20, 2023, 7:11 p.m. UTC | #1
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
>
  
Ken Matsui Oct. 20, 2023, 8 p.m. UTC | #2
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
> >
>
  
Jason Merrill Oct. 23, 2023, 8:27 p.m. UTC | #3
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
  
Ken Matsui Oct. 23, 2023, 9:08 p.m. UTC | #4
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
>
  

Patch

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 ::,