[v23,02/33] c-family, c++: Look up built-in traits via identifier node
Checks
Commit Message
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
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
>
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
> >
>
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
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
>
@@ -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 },
@@ -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,
@@ -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;
@@ -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)
@@ -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 ();
@@ -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 ::,