[v19,02/40] c-family, c++: Look up built-in traits through gperf
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 gperf to look up the specific trait. Rather than holding
traits as keywords, we set all trait identifiers as cik_trait, which is a new
cp_identifier_kind. As cik_reserved_for_udlit was unused and
cp_identifier_kind is 3 bits, we replaced the unused field with the new
cik_trait. Also, the later patch handles a subsequent token to the built-in
identifier so that we accept the use of non-function-like built-in trait
identifiers.
gcc/c-family/ChangeLog:
* c-common.cc (c_common_reswords): Remove all mappings of
built-in traits.
* c-common.h (enum rid): Remove all RID values for built-in traits.
gcc/cp/ChangeLog:
* Make-lang.in: Add targets to generate cp-trait.gperf and
cp-trait.h.
* cp-objcp-common.cc (names_builtin_p): Remove all RID value
cases for built-in traits. Check for built-in traits via
the new cik_trait identifier.
* cp-tree.h (cik_reserved_for_udlit): Rename to ...
(cik_trait): ... this.
(IDENTIFIER_ANY_OP_P): Exclude cik_trait.
(IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
* lex.cc (init_cp_traits): New function to set cik_trait for all
built-in trait identifiers.
(cxx_init): Call init_cp_traits function.
* parser.cc (cp_lexer_lookup_trait): New function to look up a
built-in trait from a token by gperf.
(cp_lexer_lookup_trait_expr): Likewise, look up an
expression-yielding built-in trait.
(cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
built-in trait.
(cp_keyword_starts_decl_specifier_p): Remove all RID value cases
for built-in traits.
(cp_lexer_next_token_is_decl_specifier_keyword): Handle
type-yielding built-in traits.
(cp_parser_primary_expression): Remove all RID value cases for
built-in traits. Handle expression-yielding built-in traits.
(cp_parser_trait): Handle cp_trait instead of enum rid.
(cp_parser_simple_type_specifier): Remove all RID value cases
for built-in traits. Handle type-yielding built-in traits.
* cp-trait-head.in: New file.
* cp-trait.gperf: New file.
* cp-trait.h: New file.
Co-authored-by: Patrick Palka <ppalka@redhat.com>
Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
gcc/c-family/c-common.cc | 7 --
gcc/c-family/c-common.h | 5 -
gcc/cp/Make-lang.in | 26 ++++
gcc/cp/cp-objcp-common.cc | 8 +-
gcc/cp/cp-trait-head.in | 30 +++++
gcc/cp/cp-trait.gperf | 74 ++++++++++++
gcc/cp/cp-trait.h | 247 ++++++++++++++++++++++++++++++++++++++
gcc/cp/cp-tree.h | 14 ++-
gcc/cp/lex.cc | 19 +++
gcc/cp/parser.cc | 132 ++++++++++++--------
10 files changed, 492 insertions(+), 70 deletions(-)
create mode 100644 gcc/cp/cp-trait-head.in
create mode 100644 gcc/cp/cp-trait.gperf
create mode 100644 gcc/cp/cp-trait.h
Comments
On Fri, 13 Oct 2023, Ken Matsui wrote:
> Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> once in a C++ translation unit, this patch removes all RID values for built-in
> traits and uses gperf to look up the specific trait. Rather than holding
> traits as keywords, we set all trait identifiers as cik_trait, which is a new
> cp_identifier_kind. As cik_reserved_for_udlit was unused and
> cp_identifier_kind is 3 bits, we replaced the unused field with the new
> cik_trait. Also, the later patch handles a subsequent token to the built-in
> identifier so that we accept the use of non-function-like built-in trait
> identifiers.
Awesome! It's great we won't have to rename any existing identifiers in
libstdc++ with this approach.
I think this patch looks perfect, assuming we want to stick with the gperf
approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
field which is currently only used for operator name identifiers to
optimize looking up operator information. Could we reuse this field for
IDENTIFIER_TRAIT_P identifiers as well in order to store their
corresponding cp_trait_kind? If so then I think we wouldn't need to use
gperf for the built-in traits at all, since the mapping from identifier
to cp_trait_kind would be implicit in each IDENTIFIER node, which would
perhaps be a nice simplification (and just as fast if not faster than gperf)?
>
> gcc/c-family/ChangeLog:
>
> * c-common.cc (c_common_reswords): Remove all mappings of
> built-in traits.
> * c-common.h (enum rid): Remove all RID values for built-in traits.
>
> gcc/cp/ChangeLog:
>
> * Make-lang.in: Add targets to generate cp-trait.gperf and
> cp-trait.h.
> * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> cases for built-in traits. Check for built-in traits via
> the new cik_trait identifier.
> * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> (cik_trait): ... this.
> (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> * lex.cc (init_cp_traits): New function to set cik_trait for all
> built-in trait identifiers.
> (cxx_init): Call init_cp_traits function.
> * parser.cc (cp_lexer_lookup_trait): New function to look up a
> built-in trait from a token by gperf.
> (cp_lexer_lookup_trait_expr): Likewise, look up an
> expression-yielding built-in trait.
> (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> built-in trait.
> (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> for built-in traits.
> (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> type-yielding built-in traits.
> (cp_parser_primary_expression): Remove all RID value cases for
> built-in traits. Handle expression-yielding built-in traits.
> (cp_parser_trait): Handle cp_trait instead of enum rid.
> (cp_parser_simple_type_specifier): Remove all RID value cases
> for built-in traits. Handle type-yielding built-in traits.
> * cp-trait-head.in: New file.
> * cp-trait.gperf: New file.
> * cp-trait.h: New file.
>
> Co-authored-by: Patrick Palka <ppalka@redhat.com>
> Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> ---
> gcc/c-family/c-common.cc | 7 --
> gcc/c-family/c-common.h | 5 -
> gcc/cp/Make-lang.in | 26 ++++
> gcc/cp/cp-objcp-common.cc | 8 +-
> gcc/cp/cp-trait-head.in | 30 +++++
> gcc/cp/cp-trait.gperf | 74 ++++++++++++
> gcc/cp/cp-trait.h | 247 ++++++++++++++++++++++++++++++++++++++
> gcc/cp/cp-tree.h | 14 ++-
> gcc/cp/lex.cc | 19 +++
> gcc/cp/parser.cc | 132 ++++++++++++--------
> 10 files changed, 492 insertions(+), 70 deletions(-)
> create mode 100644 gcc/cp/cp-trait-head.in
> create mode 100644 gcc/cp/cp-trait.gperf
> create mode 100644 gcc/cp/cp-trait.h
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index f044db5b797..21fd333ef57 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> { "wchar_t", RID_WCHAR, D_CXXONLY },
> { "while", RID_WHILE, 0 },
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> - { NAME, RID_##CODE, D_CXXONLY },
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> - /* An alias for __is_same. */
> - { "__is_same_as", RID_IS_SAME, D_CXXONLY },
> -
> /* C++ transactional memory. */
> { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 1fdba7ef3ea..051a442e0f4 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -168,11 +168,6 @@ enum rid
> RID_BUILTIN_LAUNDER,
> RID_BUILTIN_BIT_CAST,
>
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> - RID_##CODE,
> -#include "cp/cp-trait.def"
> -#undef DEFTRAIT
> -
> /* C++11 */
> RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
>
> diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> index 2727fb7f8cc..a67d1c3e9f3 100644
> --- a/gcc/cp/Make-lang.in
> +++ b/gcc/cp/Make-lang.in
> @@ -34,6 +34,8 @@
> # - the compiler proper (eg: cc1plus)
> # - define the names for selecting the language in LANGUAGES.
>
> +AWK = @AWK@
> +
> # Actual names to use when installing a native compiler.
> CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> @@ -186,6 +188,30 @@ endif
> # This is the file that depends on the generated header file.
> cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
>
> +# We always need the dependency on the .gperf file
> +# because it itself is generated.
> +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> +else
> +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> +endif
> + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> + $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> +
> +# The cp-trait.gperf file itself is generated from
> +# cp-trait-head.in and cp-trait.def files.
> +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> + cat $< > $@
> + $(AWK) -F', *' '/^DEFTRAIT_/ { \
> + type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> + gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> + gsub(/\)/, "", $$3); \
> + print $$2", CPTK_" $$1", "$$3", "type; \
> + }' $(srcdir)/cp/cp-trait.def >> $@
> +
> +# This is the file that depends on the generated header file.
> +cp/parser.o: $(srcdir)/cp/cp-trait.h
> +
> components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
>
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 93b027b80ce..b1adacfec07 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> }
> }
>
> + /* Check for built-in traits. */
> + if (IDENTIFIER_TRAIT_P (id))
> + return true;
> +
> /* Also detect common reserved C++ words that aren't strictly built-in
> functions. */
> switch (C_RID_CODE (id))
> @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> case RID_BUILTIN_ASSOC_BARRIER:
> case RID_BUILTIN_BIT_CAST:
> case RID_OFFSETOF:
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> - case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> return true;
> default:
> break;
> diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> new file mode 100644
> index 00000000000..9357eea1238
> --- /dev/null
> +++ b/gcc/cp/cp-trait-head.in
> @@ -0,0 +1,30 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +%}
> +struct cp_trait {
> + const char *name;
> + enum cp_trait_kind kind;
> + short arity;
> + bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> new file mode 100644
> index 00000000000..47e3c1af499
> --- /dev/null
> +++ b/gcc/cp/cp-trait.gperf
> @@ -0,0 +1,74 @@
> +%language=C++
> +%define class-name cp_trait_lookup
> +%struct-type
> +%{
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +%}
> +struct cp_trait {
> + const char *name;
> + enum cp_trait_kind kind;
> + short arity;
> + bool type;
> +};
> +%%
> +"__is_same_as", CPTK_IS_SAME, 2, false
> +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> +"__is_class", CPTK_IS_CLASS, 1, false
> +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> +"__is_empty", CPTK_IS_EMPTY, 1, false
> +"__is_enum", CPTK_IS_ENUM, 1, false
> +"__is_final", CPTK_IS_FINAL, 1, false
> +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> +"__is_pod", CPTK_IS_POD, 1, false
> +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> +"__is_same", CPTK_IS_SAME, 2, false
> +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> +"__is_union", CPTK_IS_UNION, 1, false
> +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> +"__remove_cv", CPTK_REMOVE_CV, 1, true
> +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> +"__bases", CPTK_BASES, 1, true
> +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> new file mode 100644
> index 00000000000..97ba8492d15
> --- /dev/null
> +++ b/gcc/cp/cp-trait.h
> @@ -0,0 +1,247 @@
> +/* C++ code produced by gperf version 3.1 */
> +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf */
> +
> +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> +/* The character set is not based on ISO-646. */
> +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> +#endif
> +
> +#line 4 "../../gcc/cp/cp-trait.gperf"
> +
> +/* Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +#line 23 "../../gcc/cp/cp-trait.gperf"
> +struct cp_trait {
> + const char *name;
> + enum cp_trait_kind kind;
> + short arity;
> + bool type;
> +};
> +/* maximum key range = 79, duplicates = 0 */
> +
> +class cp_trait_lookup
> +{
> +private:
> + static inline unsigned int hash (const char *str, size_t len);
> +public:
> + static const struct cp_trait *find (const char *str, size_t len);
> +};
> +
> +inline unsigned int
> +cp_trait_lookup::hash (const char *str, size_t len)
> +{
> + static const unsigned char asso_values[] =
> + {
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 1, 86, 86,
> + 0, 35, 86, 0, 86, 0, 86, 86, 10, 10,
> + 50, 15, 55, 86, 30, 5, 15, 0, 86, 86,
> + 86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> + 86, 86, 86, 86, 86, 86
> + };
> + unsigned int hval = len;
> +
> + switch (hval)
> + {
> + default:
> + hval += asso_values[static_cast<unsigned char>(str[7])];
> + /*FALLTHROUGH*/
> + case 7:
> + break;
> + }
> + return hval;
> +}
> +
> +const struct cp_trait *
> +cp_trait_lookup::find (const char *str, size_t len)
> +{
> + enum
> + {
> + TOTAL_KEYWORDS = 45,
> + MIN_WORD_LENGTH = 7,
> + MAX_WORD_LENGTH = 37,
> + MIN_HASH_VALUE = 7,
> + MAX_HASH_VALUE = 85
> + };
> +
> + static const struct cp_trait wordlist[] =
> + {
> +#line 73 "../../gcc/cp/cp-trait.gperf"
> + {"__bases", CPTK_BASES, 1, true},
> +#line 56 "../../gcc/cp/cp-trait.gperf"
> + {"__is_pod", CPTK_IS_POD, 1, false},
> +#line 48 "../../gcc/cp/cp-trait.gperf"
> + {"__is_enum", CPTK_IS_ENUM, 1, false},
> +#line 64 "../../gcc/cp/cp-trait.gperf"
> + {"__is_union", CPTK_IS_UNION, 1, false},
> +#line 44 "../../gcc/cp/cp-trait.gperf"
> + {"__is_class", CPTK_IS_CLASS, 1, false},
> +#line 60 "../../gcc/cp/cp-trait.gperf"
> + {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> +#line 41 "../../gcc/cp/cp-trait.gperf"
> + {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> +#line 72 "../../gcc/cp/cp-trait.gperf"
> + {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> +#line 43 "../../gcc/cp/cp-trait.gperf"
> + {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> +#line 40 "../../gcc/cp/cp-trait.gperf"
> + {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> +#line 58 "../../gcc/cp/cp-trait.gperf"
> + {"__is_same", CPTK_IS_SAME, 2, false},
> +#line 42 "../../gcc/cp/cp-trait.gperf"
> + {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> +#line 59 "../../gcc/cp/cp-trait.gperf"
> + {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> +#line 30 "../../gcc/cp/cp-trait.gperf"
> + {"__is_same_as", CPTK_IS_SAME, 2, false},
> +#line 63 "../../gcc/cp/cp-trait.gperf"
> + {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> +#line 39 "../../gcc/cp/cp-trait.gperf"
> + {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> +#line 61 "../../gcc/cp/cp-trait.gperf"
> + {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> +#line 57 "../../gcc/cp/cp-trait.gperf"
> + {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> +#line 71 "../../gcc/cp/cp-trait.gperf"
> + {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> +#line 62 "../../gcc/cp/cp-trait.gperf"
> + {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> +#line 74 "../../gcc/cp/cp-trait.gperf"
> + {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> +#line 51 "../../gcc/cp/cp-trait.gperf"
> + {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> +#line 33 "../../gcc/cp/cp-trait.gperf"
> + {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> +#line 31 "../../gcc/cp/cp-trait.gperf"
> + {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> +#line 55 "../../gcc/cp/cp-trait.gperf"
> + {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> +#line 52 "../../gcc/cp/cp-trait.gperf"
> + {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> +#line 54 "../../gcc/cp/cp-trait.gperf"
> + {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> +#line 32 "../../gcc/cp/cp-trait.gperf"
> + {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> +#line 53 "../../gcc/cp/cp-trait.gperf"
> + {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> +#line 50 "../../gcc/cp/cp-trait.gperf"
> + {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> +#line 67 "../../gcc/cp/cp-trait.gperf"
> + {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> +#line 36 "../../gcc/cp/cp-trait.gperf"
> + {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> +#line 68 "../../gcc/cp/cp-trait.gperf"
> + {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> +#line 34 "../../gcc/cp/cp-trait.gperf"
> + {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> +#line 69 "../../gcc/cp/cp-trait.gperf"
> + {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> +#line 37 "../../gcc/cp/cp-trait.gperf"
> + {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> +#line 35 "../../gcc/cp/cp-trait.gperf"
> + {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> +#line 49 "../../gcc/cp/cp-trait.gperf"
> + {"__is_final", CPTK_IS_FINAL, 1, false},
> +#line 47 "../../gcc/cp/cp-trait.gperf"
> + {"__is_empty", CPTK_IS_EMPTY, 1, false},
> +#line 46 "../../gcc/cp/cp-trait.gperf"
> + {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> +#line 45 "../../gcc/cp/cp-trait.gperf"
> + {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> +#line 66 "../../gcc/cp/cp-trait.gperf"
> + {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> +#line 65 "../../gcc/cp/cp-trait.gperf"
> + {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> +#line 70 "../../gcc/cp/cp-trait.gperf"
> + {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> +#line 38 "../../gcc/cp/cp-trait.gperf"
> + {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> + };
> +
> + static const signed char lookup[] =
> + {
> + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, -1,
> + 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> + 19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> + 29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> + -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> + 41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> + -1, 44
> + };
> +
> + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> + {
> + unsigned int key = hash (str, len);
> +
> + if (key <= MAX_HASH_VALUE)
> + {
> + int index = lookup[key];
> +
> + if (index >= 0)
> + {
> + const char *s = wordlist[index].name;
> +
> + if (*str == *s && !strcmp (str + 1, s + 1))
> + return &wordlist[index];
> + }
> + }
> + }
> + return 0;
> +}
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 6e34952da99..62e134886fb 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> cik_simple_op = 4, /* Non-assignment operator name. */
> cik_assign_op = 5, /* An assignment operator name. */
> cik_conv_op = 6, /* Conversion operator name. */
> - cik_reserved_for_udlit = 7, /* Not yet in use */
> + cik_trait = 7, /* Built-in trait name. */
> cik_max
> };
>
> @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> & IDENTIFIER_KIND_BIT_0 (NODE))
>
> /* True if this identifier is for any operator name (including
> - conversions). Value 4, 5, 6 or 7. */
> + conversions). Value 4, 5, or 6. */
> #define IDENTIFIER_ANY_OP_P(NODE) \
> - (IDENTIFIER_KIND_BIT_2 (NODE))
> + (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
>
> /* True if this identifier is for an overloaded operator. Values 4, 5. */
> #define IDENTIFIER_OVL_OP_P(NODE) \
> @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> & IDENTIFIER_KIND_BIT_0 (NODE))
>
> /* True if this identifier is the name of a type-conversion
> - operator. Value 7. */
> + operator. Value 6. */
> #define IDENTIFIER_CONV_OP_P(NODE) \
> (IDENTIFIER_ANY_OP_P (NODE) \
> & IDENTIFIER_KIND_BIT_1 (NODE) \
> & (!IDENTIFIER_KIND_BIT_0 (NODE)))
>
> +/* True if this identifier is the name of a built-in trait. */
> +#define IDENTIFIER_TRAIT_P(NODE) \
> + (IDENTIFIER_KIND_BIT_0 (NODE) \
> + && IDENTIFIER_KIND_BIT_1 (NODE) \
> + && IDENTIFIER_KIND_BIT_2 (NODE))
> +
> /* True if this identifier is a new or delete operator. */
> #define IDENTIFIER_NEWDEL_OP_P(NODE) \
> (IDENTIFIER_OVL_OP_P (NODE) \
> diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> index 64bcfb18196..f6e1f6a4075 100644
> --- a/gcc/cp/lex.cc
> +++ b/gcc/cp/lex.cc
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
> #include "langhooks.h"
>
> static int interface_strcmp (const char *);
> +static void init_cp_traits (void);
> static void init_cp_pragma (void);
>
> static tree parse_strconst_pragma (const char *, int);
> @@ -283,6 +284,23 @@ init_reswords (void)
> }
> }
>
> +/* Initialize the C++ traits. */
> +static void
> +init_cp_traits (void)
> +{
> + tree id;
> +
> +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> + id = get_identifier (NAME); \
> + set_identifier_kind (id, cik_trait);
> +#include "cp/cp-trait.def"
> +#undef DEFTRAIT
> +
> + /* An alias for __is_same. */
> + id = get_identifier ("__is_same_as");
> + set_identifier_kind (id, cik_trait);
> +}
> +
> static void
> init_cp_pragma (void)
> {
> @@ -324,6 +342,7 @@ cxx_init (void)
> input_location = BUILTINS_LOCATION;
>
> init_reswords ();
> + init_cp_traits ();
> init_tree ();
> init_cp_semantics ();
> init_operators ();
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index f3abae716fe..39952893ffa 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
> #include "contracts.h"
> #include "bitmap.h"
> #include "builtins.h"
> +#include "cp-trait.h"
>
>
> /* The lexer. */
> @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> (cp_lexer *) ATTRIBUTE_UNUSED;
> static void cp_lexer_stop_debugging
> (cp_lexer *) ATTRIBUTE_UNUSED;
> +static const cp_trait *cp_lexer_lookup_trait
> + (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_expr
> + (const cp_token *);
> +static const cp_trait *cp_lexer_lookup_trait_type
> + (const cp_token *);
>
> static cp_token_cache *cp_token_cache_new
> (cp_token *, cp_token *);
> @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> case RID_CONSTEVAL:
> return true;
>
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> - case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> - return true;
> -
> default:
> if (keyword >= RID_FIRST_INT_N
> && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> }
> }
>
> +/* Look ups the corresponding built-in trait if a given token is
> + a built-in trait. Otherwise, returns nullptr. */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait (const cp_token *token)
> +{
> + tree id = token->u.value;
> +
> + if (token->type == CPP_NAME
> + && TREE_CODE (id) == IDENTIFIER_NODE
> + && IDENTIFIER_TRAIT_P (id))
> + {
> + const char *id_str = IDENTIFIER_POINTER (id);
> + const int id_len = IDENTIFIER_LENGTH (id);
> + return cp_trait_lookup::find (id_str, id_len);
> + }
> + return nullptr;
> +}
> +
> +/* Similarly, but only if the token is an expression-yielding
> + built-in trait. */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_expr (const cp_token *token)
> +{
> + const cp_trait *trait = cp_lexer_lookup_trait (token);
> + if (trait && !trait->type)
> + return trait;
> +
> + return nullptr;
> +}
> +
> +/* Similarly, but only if the token is a type-yielding
> + built-in trait. */
> +
> +static const cp_trait *
> +cp_lexer_lookup_trait_type (const cp_token *token)
> +{
> + const cp_trait *trait = cp_lexer_lookup_trait (token);
> + if (trait && trait->type)
> + return trait;
> +
> + return nullptr;
> +}
> +
> /* Return true if the next token is a keyword for a decl-specifier. */
>
> static bool
> @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> cp_token *token;
>
> token = cp_lexer_peek_token (lexer);
> + if (cp_lexer_lookup_trait_type (token))
> + return true;
> return cp_keyword_starts_decl_specifier_p (token->keyword);
> }
>
> @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> static tree cp_parser_sizeof_operand
> (cp_parser *, enum rid);
> static cp_expr cp_parser_trait
> - (cp_parser *, enum rid);
> + (cp_parser *, const cp_trait *);
> static bool cp_parser_declares_only_class_p
> (cp_parser *);
> static void cp_parser_set_storage_class
> @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> case RID_OFFSETOF:
> return cp_parser_builtin_offsetof (parser);
>
> -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> - case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_EXPR
> - return cp_parser_trait (parser, token->keyword);
> -
> // C++ concepts
> case RID_REQUIRES:
> return cp_parser_requires_expression (parser);
> @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> `::' as the beginning of a qualified-id, or the "operator"
> keyword. */
> case CPP_NAME:
> + {
> + const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> + if (trait)
> + return cp_parser_trait (parser, trait);
> + }
> + /* FALLTHRU */
> case CPP_SCOPE:
> case CPP_TEMPLATE_ID:
> case CPP_NESTED_NAME_SPECIFIER:
> @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> /* Parse a builtin trait expression or type. */
>
> static cp_expr
> -cp_parser_trait (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> {
> - cp_trait_kind kind;
> tree type1, type2 = NULL_TREE;
> - bool binary = false;
> - bool variadic = false;
> - bool type = false;
> -
> - switch (keyword)
> - {
> -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> - case RID_##CODE: \
> - kind = CPTK_##CODE; \
> - binary = (ARITY == 2); \
> - variadic = (ARITY == -1); \
> - type = (TCC == tcc_type); \
> - break;
> -#include "cp-trait.def"
> -#undef DEFTRAIT
> - default:
> - gcc_unreachable ();
> - }
> + const bool binary = (trait->arity == 2);
> + const bool variadic = (trait->arity == -1);
>
> /* Get location of initial token. */
> location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> cp_lexer_consume_token (parser->lexer);
>
> matching_parens parens;
> - if (kind == CPTK_TYPE_PACK_ELEMENT)
> + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> cp_parser_require (parser, CPP_LESS, RT_LESS);
> else
> parens.require_open (parser);
>
> - if (kind == CPTK_IS_DEDUCIBLE)
> + if (trait->kind == CPTK_IS_DEDUCIBLE)
> {
> const cp_token* token = cp_lexer_peek_token (parser->lexer);
> type1 = cp_parser_id_expression (parser,
> @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> /*optional_p=*/false);
> type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> }
> - else if (kind == CPTK_TYPE_PACK_ELEMENT)
> + else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> /* __type_pack_element takes an expression as its first argument and uses
> template-id syntax instead of function call syntax (for consistency
> with Clang). We special case these properties of __type_pack_element
> @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> if (type1 == error_mark_node)
> return error_mark_node;
>
> - if (kind == CPTK_TYPE_PACK_ELEMENT)
> + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> {
> cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> tree trailing = cp_parser_enclosed_template_argument_list (parser);
> @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> }
>
> location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> - if (kind == CPTK_TYPE_PACK_ELEMENT)
> + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> /* cp_parser_enclosed_template_argument_list above already took care
> of parsing the closing '>'. */;
> else
> @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
>
> /* Complete the trait expression, which may mean either processing
> the trait expr now or saving it for template instantiation. */
> - switch (kind)
> + switch (trait->kind)
> {
> case CPTK_BASES:
> return cp_expr (finish_bases (type1, false), trait_loc);
> case CPTK_DIRECT_BASES:
> return cp_expr (finish_bases (type1, true), trait_loc);
> default:
> - if (type)
> - return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> + if (trait->type)
> + return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> else
> - return finish_trait_expr (trait_loc, kind, type1, type2);
> + return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> }
> }
>
> @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>
> return type;
>
> -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> - case RID_##CODE:
> -#include "cp-trait.def"
> -#undef DEFTRAIT_TYPE
> - type = cp_parser_trait (parser, token->keyword);
> + default:
> + break;
> + }
> +
> + /* If token is a type-yielding built-in traits, parse it. */
> + const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> + if (trait)
> + {
> + type = cp_parser_trait (parser, trait);
> if (decl_specs)
> cp_parser_set_decl_spec_type (decl_specs, type,
> token,
> /*type_definition_p=*/false);
>
> return type;
> -
> - default:
> - break;
> }
>
> /* If token is an already-parsed decltype not followed by ::,
> --
> 2.42.0
>
>
On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Fri, 13 Oct 2023, Ken Matsui wrote:
>
> > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > once in a C++ translation unit, this patch removes all RID values for built-in
> > traits and uses gperf to look up the specific trait. Rather than holding
> > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > cp_identifier_kind. As cik_reserved_for_udlit was unused and
> > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > cik_trait. Also, the later patch handles a subsequent token to the built-in
> > identifier so that we accept the use of non-function-like built-in trait
> > identifiers.
>
> Awesome! It's great we won't have to rename any existing identifiers in
> libstdc++ with this approach.
>
> I think this patch looks perfect, assuming we want to stick with the gperf
> approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> field which is currently only used for operator name identifiers to
> optimize looking up operator information. Could we reuse this field for
> IDENTIFIER_TRAIT_P identifiers as well in order to store their
> corresponding cp_trait_kind? If so then I think we wouldn't need to use
> gperf for the built-in traits at all, since the mapping from identifier
> to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> perhaps be a nice simplification (and just as fast if not faster than gperf)?
>
Thank you! I think this way decreases the size of the compiler even if
we do not see speed improvements. Since IDENTIFIER_CP_INDEX
(base.u.bits.address_space) is an unsigned char (addr_space_t), we can
have only up to 255 traits. Is this acceptable?
> >
> > gcc/c-family/ChangeLog:
> >
> > * c-common.cc (c_common_reswords): Remove all mappings of
> > built-in traits.
> > * c-common.h (enum rid): Remove all RID values for built-in traits.
> >
> > gcc/cp/ChangeLog:
> >
> > * Make-lang.in: Add targets to generate cp-trait.gperf and
> > cp-trait.h.
> > * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > cases for built-in traits. Check for built-in traits via
> > the new cik_trait identifier.
> > * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> > (cik_trait): ... this.
> > (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > * lex.cc (init_cp_traits): New function to set cik_trait for all
> > built-in trait identifiers.
> > (cxx_init): Call init_cp_traits function.
> > * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > built-in trait from a token by gperf.
> > (cp_lexer_lookup_trait_expr): Likewise, look up an
> > expression-yielding built-in trait.
> > (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > built-in trait.
> > (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > for built-in traits.
> > (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > type-yielding built-in traits.
> > (cp_parser_primary_expression): Remove all RID value cases for
> > built-in traits. Handle expression-yielding built-in traits.
> > (cp_parser_trait): Handle cp_trait instead of enum rid.
> > (cp_parser_simple_type_specifier): Remove all RID value cases
> > for built-in traits. Handle type-yielding built-in traits.
> > * cp-trait-head.in: New file.
> > * cp-trait.gperf: New file.
> > * cp-trait.h: New file.
> >
> > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > ---
> > gcc/c-family/c-common.cc | 7 --
> > gcc/c-family/c-common.h | 5 -
> > gcc/cp/Make-lang.in | 26 ++++
> > gcc/cp/cp-objcp-common.cc | 8 +-
> > gcc/cp/cp-trait-head.in | 30 +++++
> > gcc/cp/cp-trait.gperf | 74 ++++++++++++
> > gcc/cp/cp-trait.h | 247 ++++++++++++++++++++++++++++++++++++++
> > gcc/cp/cp-tree.h | 14 ++-
> > gcc/cp/lex.cc | 19 +++
> > gcc/cp/parser.cc | 132 ++++++++++++--------
> > 10 files changed, 492 insertions(+), 70 deletions(-)
> > create mode 100644 gcc/cp/cp-trait-head.in
> > create mode 100644 gcc/cp/cp-trait.gperf
> > create mode 100644 gcc/cp/cp-trait.h
> >
> > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > index f044db5b797..21fd333ef57 100644
> > --- a/gcc/c-family/c-common.cc
> > +++ b/gcc/c-family/c-common.cc
> > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > { "wchar_t", RID_WCHAR, D_CXXONLY },
> > { "while", RID_WHILE, 0 },
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > - { NAME, RID_##CODE, D_CXXONLY },
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > - /* An alias for __is_same. */
> > - { "__is_same_as", RID_IS_SAME, D_CXXONLY },
> > -
> > /* C++ transactional memory. */
> > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 1fdba7ef3ea..051a442e0f4 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -168,11 +168,6 @@ enum rid
> > RID_BUILTIN_LAUNDER,
> > RID_BUILTIN_BIT_CAST,
> >
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > - RID_##CODE,
> > -#include "cp/cp-trait.def"
> > -#undef DEFTRAIT
> > -
> > /* C++11 */
> > RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> >
> > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > index 2727fb7f8cc..a67d1c3e9f3 100644
> > --- a/gcc/cp/Make-lang.in
> > +++ b/gcc/cp/Make-lang.in
> > @@ -34,6 +34,8 @@
> > # - the compiler proper (eg: cc1plus)
> > # - define the names for selecting the language in LANGUAGES.
> >
> > +AWK = @AWK@
> > +
> > # Actual names to use when installing a native compiler.
> > CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> > GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > @@ -186,6 +188,30 @@ endif
> > # This is the file that depends on the generated header file.
> > cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> >
> > +# We always need the dependency on the .gperf file
> > +# because it itself is generated.
> > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > +else
> > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > +endif
> > + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > + $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > +
> > +# The cp-trait.gperf file itself is generated from
> > +# cp-trait-head.in and cp-trait.def files.
> > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > + cat $< > $@
> > + $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > + type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > + gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > + gsub(/\)/, "", $$3); \
> > + print $$2", CPTK_" $$1", "$$3", "type; \
> > + }' $(srcdir)/cp/cp-trait.def >> $@
> > +
> > +# This is the file that depends on the generated header file.
> > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > +
> > components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> > components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> >
> > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > index 93b027b80ce..b1adacfec07 100644
> > --- a/gcc/cp/cp-objcp-common.cc
> > +++ b/gcc/cp/cp-objcp-common.cc
> > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > }
> > }
> >
> > + /* Check for built-in traits. */
> > + if (IDENTIFIER_TRAIT_P (id))
> > + return true;
> > +
> > /* Also detect common reserved C++ words that aren't strictly built-in
> > functions. */
> > switch (C_RID_CODE (id))
> > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > case RID_BUILTIN_ASSOC_BARRIER:
> > case RID_BUILTIN_BIT_CAST:
> > case RID_OFFSETOF:
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > - case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > return true;
> > default:
> > break;
> > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > new file mode 100644
> > index 00000000000..9357eea1238
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait-head.in
> > @@ -0,0 +1,30 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3. If not see
> > +<http://www.gnu.org/licenses/>. */
> > +%}
> > +struct cp_trait {
> > + const char *name;
> > + enum cp_trait_kind kind;
> > + short arity;
> > + bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > new file mode 100644
> > index 00000000000..47e3c1af499
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.gperf
> > @@ -0,0 +1,74 @@
> > +%language=C++
> > +%define class-name cp_trait_lookup
> > +%struct-type
> > +%{
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3. If not see
> > +<http://www.gnu.org/licenses/>. */
> > +%}
> > +struct cp_trait {
> > + const char *name;
> > + enum cp_trait_kind kind;
> > + short arity;
> > + bool type;
> > +};
> > +%%
> > +"__is_same_as", CPTK_IS_SAME, 2, false
> > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > +"__is_class", CPTK_IS_CLASS, 1, false
> > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > +"__is_enum", CPTK_IS_ENUM, 1, false
> > +"__is_final", CPTK_IS_FINAL, 1, false
> > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > +"__is_pod", CPTK_IS_POD, 1, false
> > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > +"__is_same", CPTK_IS_SAME, 2, false
> > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > +"__is_union", CPTK_IS_UNION, 1, false
> > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > +"__bases", CPTK_BASES, 1, true
> > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > new file mode 100644
> > index 00000000000..97ba8492d15
> > --- /dev/null
> > +++ b/gcc/cp/cp-trait.h
> > @@ -0,0 +1,247 @@
> > +/* C++ code produced by gperf version 3.1 */
> > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf */
> > +
> > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > +/* The character set is not based on ISO-646. */
> > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > +#endif
> > +
> > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > +
> > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify it under
> > +the terms of the GNU General Public License as published by the Free
> > +Software Foundation; either version 3, or (at your option) any later
> > +version.
> > +
> > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > +for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3. If not see
> > +<http://www.gnu.org/licenses/>. */
> > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > +struct cp_trait {
> > + const char *name;
> > + enum cp_trait_kind kind;
> > + short arity;
> > + bool type;
> > +};
> > +/* maximum key range = 79, duplicates = 0 */
> > +
> > +class cp_trait_lookup
> > +{
> > +private:
> > + static inline unsigned int hash (const char *str, size_t len);
> > +public:
> > + static const struct cp_trait *find (const char *str, size_t len);
> > +};
> > +
> > +inline unsigned int
> > +cp_trait_lookup::hash (const char *str, size_t len)
> > +{
> > + static const unsigned char asso_values[] =
> > + {
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 1, 86, 86,
> > + 0, 35, 86, 0, 86, 0, 86, 86, 10, 10,
> > + 50, 15, 55, 86, 30, 5, 15, 0, 86, 86,
> > + 86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > + 86, 86, 86, 86, 86, 86
> > + };
> > + unsigned int hval = len;
> > +
> > + switch (hval)
> > + {
> > + default:
> > + hval += asso_values[static_cast<unsigned char>(str[7])];
> > + /*FALLTHROUGH*/
> > + case 7:
> > + break;
> > + }
> > + return hval;
> > +}
> > +
> > +const struct cp_trait *
> > +cp_trait_lookup::find (const char *str, size_t len)
> > +{
> > + enum
> > + {
> > + TOTAL_KEYWORDS = 45,
> > + MIN_WORD_LENGTH = 7,
> > + MAX_WORD_LENGTH = 37,
> > + MIN_HASH_VALUE = 7,
> > + MAX_HASH_VALUE = 85
> > + };
> > +
> > + static const struct cp_trait wordlist[] =
> > + {
> > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > + {"__bases", CPTK_BASES, 1, true},
> > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_pod", CPTK_IS_POD, 1, false},
> > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_enum", CPTK_IS_ENUM, 1, false},
> > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_union", CPTK_IS_UNION, 1, false},
> > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_class", CPTK_IS_CLASS, 1, false},
> > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_same", CPTK_IS_SAME, 2, false},
> > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_same_as", CPTK_IS_SAME, 2, false},
> > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > + {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > + {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > + {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > + {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > + {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_final", CPTK_IS_FINAL, 1, false},
> > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > + {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > + {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > + {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > + {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > + {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > + };
> > +
> > + static const signed char lookup[] =
> > + {
> > + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, -1,
> > + 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > + 19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > + 29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > + -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > + 41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > + -1, 44
> > + };
> > +
> > + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > + {
> > + unsigned int key = hash (str, len);
> > +
> > + if (key <= MAX_HASH_VALUE)
> > + {
> > + int index = lookup[key];
> > +
> > + if (index >= 0)
> > + {
> > + const char *s = wordlist[index].name;
> > +
> > + if (*str == *s && !strcmp (str + 1, s + 1))
> > + return &wordlist[index];
> > + }
> > + }
> > + }
> > + return 0;
> > +}
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 6e34952da99..62e134886fb 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > cik_simple_op = 4, /* Non-assignment operator name. */
> > cik_assign_op = 5, /* An assignment operator name. */
> > cik_conv_op = 6, /* Conversion operator name. */
> > - cik_reserved_for_udlit = 7, /* Not yet in use */
> > + cik_trait = 7, /* Built-in trait name. */
> > cik_max
> > };
> >
> > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> > /* True if this identifier is for any operator name (including
> > - conversions). Value 4, 5, 6 or 7. */
> > + conversions). Value 4, 5, or 6. */
> > #define IDENTIFIER_ANY_OP_P(NODE) \
> > - (IDENTIFIER_KIND_BIT_2 (NODE))
> > + (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> >
> > /* True if this identifier is for an overloaded operator. Values 4, 5. */
> > #define IDENTIFIER_OVL_OP_P(NODE) \
> > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > & IDENTIFIER_KIND_BIT_0 (NODE))
> >
> > /* True if this identifier is the name of a type-conversion
> > - operator. Value 7. */
> > + operator. Value 6. */
> > #define IDENTIFIER_CONV_OP_P(NODE) \
> > (IDENTIFIER_ANY_OP_P (NODE) \
> > & IDENTIFIER_KIND_BIT_1 (NODE) \
> > & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> >
> > +/* True if this identifier is the name of a built-in trait. */
> > +#define IDENTIFIER_TRAIT_P(NODE) \
> > + (IDENTIFIER_KIND_BIT_0 (NODE) \
> > + && IDENTIFIER_KIND_BIT_1 (NODE) \
> > + && IDENTIFIER_KIND_BIT_2 (NODE))
> > +
> > /* True if this identifier is a new or delete operator. */
> > #define IDENTIFIER_NEWDEL_OP_P(NODE) \
> > (IDENTIFIER_OVL_OP_P (NODE) \
> > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > index 64bcfb18196..f6e1f6a4075 100644
> > --- a/gcc/cp/lex.cc
> > +++ b/gcc/cp/lex.cc
> > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
> > #include "langhooks.h"
> >
> > static int interface_strcmp (const char *);
> > +static void init_cp_traits (void);
> > static void init_cp_pragma (void);
> >
> > static tree parse_strconst_pragma (const char *, int);
> > @@ -283,6 +284,23 @@ init_reswords (void)
> > }
> > }
> >
> > +/* Initialize the C++ traits. */
> > +static void
> > +init_cp_traits (void)
> > +{
> > + tree id;
> > +
> > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > + id = get_identifier (NAME); \
> > + set_identifier_kind (id, cik_trait);
> > +#include "cp/cp-trait.def"
> > +#undef DEFTRAIT
> > +
> > + /* An alias for __is_same. */
> > + id = get_identifier ("__is_same_as");
> > + set_identifier_kind (id, cik_trait);
> > +}
> > +
> > static void
> > init_cp_pragma (void)
> > {
> > @@ -324,6 +342,7 @@ cxx_init (void)
> > input_location = BUILTINS_LOCATION;
> >
> > init_reswords ();
> > + init_cp_traits ();
> > init_tree ();
> > init_cp_semantics ();
> > init_operators ();
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index f3abae716fe..39952893ffa 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
> > #include "contracts.h"
> > #include "bitmap.h"
> > #include "builtins.h"
> > +#include "cp-trait.h"
> >
> >
> > /* The lexer. */
> > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> > (cp_lexer *) ATTRIBUTE_UNUSED;
> > static void cp_lexer_stop_debugging
> > (cp_lexer *) ATTRIBUTE_UNUSED;
> > +static const cp_trait *cp_lexer_lookup_trait
> > + (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_expr
> > + (const cp_token *);
> > +static const cp_trait *cp_lexer_lookup_trait_type
> > + (const cp_token *);
> >
> > static cp_token_cache *cp_token_cache_new
> > (cp_token *, cp_token *);
> > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > case RID_CONSTEVAL:
> > return true;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > - case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > - return true;
> > -
> > default:
> > if (keyword >= RID_FIRST_INT_N
> > && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > }
> > }
> >
> > +/* Look ups the corresponding built-in trait if a given token is
> > + a built-in trait. Otherwise, returns nullptr. */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait (const cp_token *token)
> > +{
> > + tree id = token->u.value;
> > +
> > + if (token->type == CPP_NAME
> > + && TREE_CODE (id) == IDENTIFIER_NODE
> > + && IDENTIFIER_TRAIT_P (id))
> > + {
> > + const char *id_str = IDENTIFIER_POINTER (id);
> > + const int id_len = IDENTIFIER_LENGTH (id);
> > + return cp_trait_lookup::find (id_str, id_len);
> > + }
> > + return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is an expression-yielding
> > + built-in trait. */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > +{
> > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > + if (trait && !trait->type)
> > + return trait;
> > +
> > + return nullptr;
> > +}
> > +
> > +/* Similarly, but only if the token is a type-yielding
> > + built-in trait. */
> > +
> > +static const cp_trait *
> > +cp_lexer_lookup_trait_type (const cp_token *token)
> > +{
> > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > + if (trait && trait->type)
> > + return trait;
> > +
> > + return nullptr;
> > +}
> > +
> > /* Return true if the next token is a keyword for a decl-specifier. */
> >
> > static bool
> > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > cp_token *token;
> >
> > token = cp_lexer_peek_token (lexer);
> > + if (cp_lexer_lookup_trait_type (token))
> > + return true;
> > return cp_keyword_starts_decl_specifier_p (token->keyword);
> > }
> >
> > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> > static tree cp_parser_sizeof_operand
> > (cp_parser *, enum rid);
> > static cp_expr cp_parser_trait
> > - (cp_parser *, enum rid);
> > + (cp_parser *, const cp_trait *);
> > static bool cp_parser_declares_only_class_p
> > (cp_parser *);
> > static void cp_parser_set_storage_class
> > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > case RID_OFFSETOF:
> > return cp_parser_builtin_offsetof (parser);
> >
> > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > - case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_EXPR
> > - return cp_parser_trait (parser, token->keyword);
> > -
> > // C++ concepts
> > case RID_REQUIRES:
> > return cp_parser_requires_expression (parser);
> > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > `::' as the beginning of a qualified-id, or the "operator"
> > keyword. */
> > case CPP_NAME:
> > + {
> > + const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > + if (trait)
> > + return cp_parser_trait (parser, trait);
> > + }
> > + /* FALLTHRU */
> > case CPP_SCOPE:
> > case CPP_TEMPLATE_ID:
> > case CPP_NESTED_NAME_SPECIFIER:
> > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > /* Parse a builtin trait expression or type. */
> >
> > static cp_expr
> > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > {
> > - cp_trait_kind kind;
> > tree type1, type2 = NULL_TREE;
> > - bool binary = false;
> > - bool variadic = false;
> > - bool type = false;
> > -
> > - switch (keyword)
> > - {
> > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > - case RID_##CODE: \
> > - kind = CPTK_##CODE; \
> > - binary = (ARITY == 2); \
> > - variadic = (ARITY == -1); \
> > - type = (TCC == tcc_type); \
> > - break;
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT
> > - default:
> > - gcc_unreachable ();
> > - }
> > + const bool binary = (trait->arity == 2);
> > + const bool variadic = (trait->arity == -1);
> >
> > /* Get location of initial token. */
> > location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > cp_lexer_consume_token (parser->lexer);
> >
> > matching_parens parens;
> > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > cp_parser_require (parser, CPP_LESS, RT_LESS);
> > else
> > parens.require_open (parser);
> >
> > - if (kind == CPTK_IS_DEDUCIBLE)
> > + if (trait->kind == CPTK_IS_DEDUCIBLE)
> > {
> > const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > type1 = cp_parser_id_expression (parser,
> > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > /*optional_p=*/false);
> > type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > }
> > - else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > + else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > /* __type_pack_element takes an expression as its first argument and uses
> > template-id syntax instead of function call syntax (for consistency
> > with Clang). We special case these properties of __type_pack_element
> > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > if (type1 == error_mark_node)
> > return error_mark_node;
> >
> > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > {
> > cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > }
> >
> > location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > /* cp_parser_enclosed_template_argument_list above already took care
> > of parsing the closing '>'. */;
> > else
> > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> >
> > /* Complete the trait expression, which may mean either processing
> > the trait expr now or saving it for template instantiation. */
> > - switch (kind)
> > + switch (trait->kind)
> > {
> > case CPTK_BASES:
> > return cp_expr (finish_bases (type1, false), trait_loc);
> > case CPTK_DIRECT_BASES:
> > return cp_expr (finish_bases (type1, true), trait_loc);
> > default:
> > - if (type)
> > - return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > + if (trait->type)
> > + return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > else
> > - return finish_trait_expr (trait_loc, kind, type1, type2);
> > + return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > }
> > }
> >
> > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> >
> > return type;
> >
> > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > - case RID_##CODE:
> > -#include "cp-trait.def"
> > -#undef DEFTRAIT_TYPE
> > - type = cp_parser_trait (parser, token->keyword);
> > + default:
> > + break;
> > + }
> > +
> > + /* If token is a type-yielding built-in traits, parse it. */
> > + const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > + if (trait)
> > + {
> > + type = cp_parser_trait (parser, trait);
> > if (decl_specs)
> > cp_parser_set_decl_spec_type (decl_specs, type,
> > token,
> > /*type_definition_p=*/false);
> >
> > return type;
> > -
> > - default:
> > - break;
> > }
> >
> > /* If token is an already-parsed decltype not followed by ::,
> > --
> > 2.42.0
> >
> >
>
On Sun, 15 Oct 2023, Ken Matsui wrote:
> On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
> >
> > On Fri, 13 Oct 2023, Ken Matsui wrote:
> >
> > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > traits and uses gperf to look up the specific trait. Rather than holding
> > > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > > cp_identifier_kind. As cik_reserved_for_udlit was unused and
> > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > cik_trait. Also, the later patch handles a subsequent token to the built-in
> > > identifier so that we accept the use of non-function-like built-in trait
> > > identifiers.
> >
> > Awesome! It's great we won't have to rename any existing identifiers in
> > libstdc++ with this approach.
> >
> > I think this patch looks perfect, assuming we want to stick with the gperf
> > approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> > field which is currently only used for operator name identifiers to
> > optimize looking up operator information. Could we reuse this field for
> > IDENTIFIER_TRAIT_P identifiers as well in order to store their
> > corresponding cp_trait_kind? If so then I think we wouldn't need to use
> > gperf for the built-in traits at all, since the mapping from identifier
> > to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> > perhaps be a nice simplification (and just as fast if not faster than gperf)?
> >
>
> Thank you! I think this way decreases the size of the compiler even if
> we do not see speed improvements. Since IDENTIFIER_CP_INDEX
> (base.u.bits.address_space) is an unsigned char (addr_space_t), we can
> have only up to 255 traits. Is this acceptable?
Good points. Given there's so far around 150 standard library traits, a
limit of 255 should last us quite a while so IMHO it's acceptable :)
>
> > >
> > > gcc/c-family/ChangeLog:
> > >
> > > * c-common.cc (c_common_reswords): Remove all mappings of
> > > built-in traits.
> > > * c-common.h (enum rid): Remove all RID values for built-in traits.
> > >
> > > gcc/cp/ChangeLog:
> > >
> > > * Make-lang.in: Add targets to generate cp-trait.gperf and
> > > cp-trait.h.
> > > * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > > cases for built-in traits. Check for built-in traits via
> > > the new cik_trait identifier.
> > > * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> > > (cik_trait): ... this.
> > > (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > > (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > > * lex.cc (init_cp_traits): New function to set cik_trait for all
> > > built-in trait identifiers.
> > > (cxx_init): Call init_cp_traits function.
> > > * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > > built-in trait from a token by gperf.
> > > (cp_lexer_lookup_trait_expr): Likewise, look up an
> > > expression-yielding built-in trait.
> > > (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > > built-in trait.
> > > (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > > for built-in traits.
> > > (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > > type-yielding built-in traits.
> > > (cp_parser_primary_expression): Remove all RID value cases for
> > > built-in traits. Handle expression-yielding built-in traits.
> > > (cp_parser_trait): Handle cp_trait instead of enum rid.
> > > (cp_parser_simple_type_specifier): Remove all RID value cases
> > > for built-in traits. Handle type-yielding built-in traits.
> > > * cp-trait-head.in: New file.
> > > * cp-trait.gperf: New file.
> > > * cp-trait.h: New file.
> > >
> > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > ---
> > > gcc/c-family/c-common.cc | 7 --
> > > gcc/c-family/c-common.h | 5 -
> > > gcc/cp/Make-lang.in | 26 ++++
> > > gcc/cp/cp-objcp-common.cc | 8 +-
> > > gcc/cp/cp-trait-head.in | 30 +++++
> > > gcc/cp/cp-trait.gperf | 74 ++++++++++++
> > > gcc/cp/cp-trait.h | 247 ++++++++++++++++++++++++++++++++++++++
> > > gcc/cp/cp-tree.h | 14 ++-
> > > gcc/cp/lex.cc | 19 +++
> > > gcc/cp/parser.cc | 132 ++++++++++++--------
> > > 10 files changed, 492 insertions(+), 70 deletions(-)
> > > create mode 100644 gcc/cp/cp-trait-head.in
> > > create mode 100644 gcc/cp/cp-trait.gperf
> > > create mode 100644 gcc/cp/cp-trait.h
> > >
> > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > index f044db5b797..21fd333ef57 100644
> > > --- a/gcc/c-family/c-common.cc
> > > +++ b/gcc/c-family/c-common.cc
> > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > > { "wchar_t", RID_WCHAR, D_CXXONLY },
> > > { "while", RID_WHILE, 0 },
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > - { NAME, RID_##CODE, D_CXXONLY },
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > - /* An alias for __is_same. */
> > > - { "__is_same_as", RID_IS_SAME, D_CXXONLY },
> > > -
> > > /* C++ transactional memory. */
> > > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > > { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > index 1fdba7ef3ea..051a442e0f4 100644
> > > --- a/gcc/c-family/c-common.h
> > > +++ b/gcc/c-family/c-common.h
> > > @@ -168,11 +168,6 @@ enum rid
> > > RID_BUILTIN_LAUNDER,
> > > RID_BUILTIN_BIT_CAST,
> > >
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > - RID_##CODE,
> > > -#include "cp/cp-trait.def"
> > > -#undef DEFTRAIT
> > > -
> > > /* C++11 */
> > > RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > >
> > > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > > index 2727fb7f8cc..a67d1c3e9f3 100644
> > > --- a/gcc/cp/Make-lang.in
> > > +++ b/gcc/cp/Make-lang.in
> > > @@ -34,6 +34,8 @@
> > > # - the compiler proper (eg: cc1plus)
> > > # - define the names for selecting the language in LANGUAGES.
> > >
> > > +AWK = @AWK@
> > > +
> > > # Actual names to use when installing a native compiler.
> > > CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> > > GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > > @@ -186,6 +188,30 @@ endif
> > > # This is the file that depends on the generated header file.
> > > cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> > >
> > > +# We always need the dependency on the .gperf file
> > > +# because it itself is generated.
> > > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > > +else
> > > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > > +endif
> > > + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > > + $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > > +
> > > +# The cp-trait.gperf file itself is generated from
> > > +# cp-trait-head.in and cp-trait.def files.
> > > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > > + cat $< > $@
> > > + $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > > + type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > > + gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > > + gsub(/\)/, "", $$3); \
> > > + print $$2", CPTK_" $$1", "$$3", "type; \
> > > + }' $(srcdir)/cp/cp-trait.def >> $@
> > > +
> > > +# This is the file that depends on the generated header file.
> > > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > > +
> > > components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> > > components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> > >
> > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > index 93b027b80ce..b1adacfec07 100644
> > > --- a/gcc/cp/cp-objcp-common.cc
> > > +++ b/gcc/cp/cp-objcp-common.cc
> > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > > }
> > > }
> > >
> > > + /* Check for built-in traits. */
> > > + if (IDENTIFIER_TRAIT_P (id))
> > > + return true;
> > > +
> > > /* Also detect common reserved C++ words that aren't strictly built-in
> > > functions. */
> > > switch (C_RID_CODE (id))
> > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > > case RID_BUILTIN_ASSOC_BARRIER:
> > > case RID_BUILTIN_BIT_CAST:
> > > case RID_OFFSETOF:
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > - case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > > return true;
> > > default:
> > > break;
> > > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > > new file mode 100644
> > > index 00000000000..9357eea1238
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait-head.in
> > > @@ -0,0 +1,30 @@
> > > +%language=C++
> > > +%define class-name cp_trait_lookup
> > > +%struct-type
> > > +%{
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3. If not see
> > > +<http://www.gnu.org/licenses/>. */
> > > +%}
> > > +struct cp_trait {
> > > + const char *name;
> > > + enum cp_trait_kind kind;
> > > + short arity;
> > > + bool type;
> > > +};
> > > +%%
> > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > > new file mode 100644
> > > index 00000000000..47e3c1af499
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait.gperf
> > > @@ -0,0 +1,74 @@
> > > +%language=C++
> > > +%define class-name cp_trait_lookup
> > > +%struct-type
> > > +%{
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3. If not see
> > > +<http://www.gnu.org/licenses/>. */
> > > +%}
> > > +struct cp_trait {
> > > + const char *name;
> > > + enum cp_trait_kind kind;
> > > + short arity;
> > > + bool type;
> > > +};
> > > +%%
> > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > > +"__is_class", CPTK_IS_CLASS, 1, false
> > > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > > +"__is_enum", CPTK_IS_ENUM, 1, false
> > > +"__is_final", CPTK_IS_FINAL, 1, false
> > > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > > +"__is_pod", CPTK_IS_POD, 1, false
> > > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > > +"__is_same", CPTK_IS_SAME, 2, false
> > > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > > +"__is_union", CPTK_IS_UNION, 1, false
> > > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > > +"__bases", CPTK_BASES, 1, true
> > > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > > new file mode 100644
> > > index 00000000000..97ba8492d15
> > > --- /dev/null
> > > +++ b/gcc/cp/cp-trait.h
> > > @@ -0,0 +1,247 @@
> > > +/* C++ code produced by gperf version 3.1 */
> > > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf */
> > > +
> > > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > > + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > > + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > > + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > > + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > > + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > > + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > > + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > > + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > > + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > > + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > > + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > > + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > > + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > > + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > > + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > > + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > > + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > > + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > > + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > > + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > > + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > > + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > > +/* The character set is not based on ISO-646. */
> > > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > > +#endif
> > > +
> > > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > > +
> > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > +
> > > +This file is part of GCC.
> > > +
> > > +GCC is free software; you can redistribute it and/or modify it under
> > > +the terms of the GNU General Public License as published by the Free
> > > +Software Foundation; either version 3, or (at your option) any later
> > > +version.
> > > +
> > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > +for more details.
> > > +
> > > +You should have received a copy of the GNU General Public License
> > > +along with GCC; see the file COPYING3. If not see
> > > +<http://www.gnu.org/licenses/>. */
> > > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > > +struct cp_trait {
> > > + const char *name;
> > > + enum cp_trait_kind kind;
> > > + short arity;
> > > + bool type;
> > > +};
> > > +/* maximum key range = 79, duplicates = 0 */
> > > +
> > > +class cp_trait_lookup
> > > +{
> > > +private:
> > > + static inline unsigned int hash (const char *str, size_t len);
> > > +public:
> > > + static const struct cp_trait *find (const char *str, size_t len);
> > > +};
> > > +
> > > +inline unsigned int
> > > +cp_trait_lookup::hash (const char *str, size_t len)
> > > +{
> > > + static const unsigned char asso_values[] =
> > > + {
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 1, 86, 86,
> > > + 0, 35, 86, 0, 86, 0, 86, 86, 10, 10,
> > > + 50, 15, 55, 86, 30, 5, 15, 0, 86, 86,
> > > + 86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > + 86, 86, 86, 86, 86, 86
> > > + };
> > > + unsigned int hval = len;
> > > +
> > > + switch (hval)
> > > + {
> > > + default:
> > > + hval += asso_values[static_cast<unsigned char>(str[7])];
> > > + /*FALLTHROUGH*/
> > > + case 7:
> > > + break;
> > > + }
> > > + return hval;
> > > +}
> > > +
> > > +const struct cp_trait *
> > > +cp_trait_lookup::find (const char *str, size_t len)
> > > +{
> > > + enum
> > > + {
> > > + TOTAL_KEYWORDS = 45,
> > > + MIN_WORD_LENGTH = 7,
> > > + MAX_WORD_LENGTH = 37,
> > > + MIN_HASH_VALUE = 7,
> > > + MAX_HASH_VALUE = 85
> > > + };
> > > +
> > > + static const struct cp_trait wordlist[] =
> > > + {
> > > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > > + {"__bases", CPTK_BASES, 1, true},
> > > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_pod", CPTK_IS_POD, 1, false},
> > > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_enum", CPTK_IS_ENUM, 1, false},
> > > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_union", CPTK_IS_UNION, 1, false},
> > > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_class", CPTK_IS_CLASS, 1, false},
> > > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_same", CPTK_IS_SAME, 2, false},
> > > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_same_as", CPTK_IS_SAME, 2, false},
> > > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > > + {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > > + {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > > + {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > > + {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > > + {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_final", CPTK_IS_FINAL, 1, false},
> > > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > > + {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > > + {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > > + {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > > + {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > > + {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > > + };
> > > +
> > > + static const signed char lookup[] =
> > > + {
> > > + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, -1,
> > > + 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > > + 19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > > + 29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > > + -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > > + 41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > > + -1, 44
> > > + };
> > > +
> > > + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > > + {
> > > + unsigned int key = hash (str, len);
> > > +
> > > + if (key <= MAX_HASH_VALUE)
> > > + {
> > > + int index = lookup[key];
> > > +
> > > + if (index >= 0)
> > > + {
> > > + const char *s = wordlist[index].name;
> > > +
> > > + if (*str == *s && !strcmp (str + 1, s + 1))
> > > + return &wordlist[index];
> > > + }
> > > + }
> > > + }
> > > + return 0;
> > > +}
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index 6e34952da99..62e134886fb 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > > cik_simple_op = 4, /* Non-assignment operator name. */
> > > cik_assign_op = 5, /* An assignment operator name. */
> > > cik_conv_op = 6, /* Conversion operator name. */
> > > - cik_reserved_for_udlit = 7, /* Not yet in use */
> > > + cik_trait = 7, /* Built-in trait name. */
> > > cik_max
> > > };
> > >
> > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > > & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > > /* True if this identifier is for any operator name (including
> > > - conversions). Value 4, 5, 6 or 7. */
> > > + conversions). Value 4, 5, or 6. */
> > > #define IDENTIFIER_ANY_OP_P(NODE) \
> > > - (IDENTIFIER_KIND_BIT_2 (NODE))
> > > + (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > >
> > > /* True if this identifier is for an overloaded operator. Values 4, 5. */
> > > #define IDENTIFIER_OVL_OP_P(NODE) \
> > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > > & IDENTIFIER_KIND_BIT_0 (NODE))
> > >
> > > /* True if this identifier is the name of a type-conversion
> > > - operator. Value 7. */
> > > + operator. Value 6. */
> > > #define IDENTIFIER_CONV_OP_P(NODE) \
> > > (IDENTIFIER_ANY_OP_P (NODE) \
> > > & IDENTIFIER_KIND_BIT_1 (NODE) \
> > > & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > >
> > > +/* True if this identifier is the name of a built-in trait. */
> > > +#define IDENTIFIER_TRAIT_P(NODE) \
> > > + (IDENTIFIER_KIND_BIT_0 (NODE) \
> > > + && IDENTIFIER_KIND_BIT_1 (NODE) \
> > > + && IDENTIFIER_KIND_BIT_2 (NODE))
> > > +
> > > /* True if this identifier is a new or delete operator. */
> > > #define IDENTIFIER_NEWDEL_OP_P(NODE) \
> > > (IDENTIFIER_OVL_OP_P (NODE) \
> > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > index 64bcfb18196..f6e1f6a4075 100644
> > > --- a/gcc/cp/lex.cc
> > > +++ b/gcc/cp/lex.cc
> > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
> > > #include "langhooks.h"
> > >
> > > static int interface_strcmp (const char *);
> > > +static void init_cp_traits (void);
> > > static void init_cp_pragma (void);
> > >
> > > static tree parse_strconst_pragma (const char *, int);
> > > @@ -283,6 +284,23 @@ init_reswords (void)
> > > }
> > > }
> > >
> > > +/* Initialize the C++ traits. */
> > > +static void
> > > +init_cp_traits (void)
> > > +{
> > > + tree id;
> > > +
> > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > + id = get_identifier (NAME); \
> > > + set_identifier_kind (id, cik_trait);
> > > +#include "cp/cp-trait.def"
> > > +#undef DEFTRAIT
> > > +
> > > + /* An alias for __is_same. */
> > > + id = get_identifier ("__is_same_as");
> > > + set_identifier_kind (id, cik_trait);
> > > +}
> > > +
> > > static void
> > > init_cp_pragma (void)
> > > {
> > > @@ -324,6 +342,7 @@ cxx_init (void)
> > > input_location = BUILTINS_LOCATION;
> > >
> > > init_reswords ();
> > > + init_cp_traits ();
> > > init_tree ();
> > > init_cp_semantics ();
> > > init_operators ();
> > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > index f3abae716fe..39952893ffa 100644
> > > --- a/gcc/cp/parser.cc
> > > +++ b/gcc/cp/parser.cc
> > > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
> > > #include "contracts.h"
> > > #include "bitmap.h"
> > > #include "builtins.h"
> > > +#include "cp-trait.h"
> > >
> > >
> > > /* The lexer. */
> > > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> > > (cp_lexer *) ATTRIBUTE_UNUSED;
> > > static void cp_lexer_stop_debugging
> > > (cp_lexer *) ATTRIBUTE_UNUSED;
> > > +static const cp_trait *cp_lexer_lookup_trait
> > > + (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > + (const cp_token *);
> > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > + (const cp_token *);
> > >
> > > static cp_token_cache *cp_token_cache_new
> > > (cp_token *, cp_token *);
> > > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > case RID_CONSTEVAL:
> > > return true;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > - case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > - return true;
> > > -
> > > default:
> > > if (keyword >= RID_FIRST_INT_N
> > > && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > }
> > > }
> > >
> > > +/* Look ups the corresponding built-in trait if a given token is
> > > + a built-in trait. Otherwise, returns nullptr. */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait (const cp_token *token)
> > > +{
> > > + tree id = token->u.value;
> > > +
> > > + if (token->type == CPP_NAME
> > > + && TREE_CODE (id) == IDENTIFIER_NODE
> > > + && IDENTIFIER_TRAIT_P (id))
> > > + {
> > > + const char *id_str = IDENTIFIER_POINTER (id);
> > > + const int id_len = IDENTIFIER_LENGTH (id);
> > > + return cp_trait_lookup::find (id_str, id_len);
> > > + }
> > > + return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is an expression-yielding
> > > + built-in trait. */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > +{
> > > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > + if (trait && !trait->type)
> > > + return trait;
> > > +
> > > + return nullptr;
> > > +}
> > > +
> > > +/* Similarly, but only if the token is a type-yielding
> > > + built-in trait. */
> > > +
> > > +static const cp_trait *
> > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > +{
> > > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > + if (trait && trait->type)
> > > + return trait;
> > > +
> > > + return nullptr;
> > > +}
> > > +
> > > /* Return true if the next token is a keyword for a decl-specifier. */
> > >
> > > static bool
> > > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > > cp_token *token;
> > >
> > > token = cp_lexer_peek_token (lexer);
> > > + if (cp_lexer_lookup_trait_type (token))
> > > + return true;
> > > return cp_keyword_starts_decl_specifier_p (token->keyword);
> > > }
> > >
> > > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> > > static tree cp_parser_sizeof_operand
> > > (cp_parser *, enum rid);
> > > static cp_expr cp_parser_trait
> > > - (cp_parser *, enum rid);
> > > + (cp_parser *, const cp_trait *);
> > > static bool cp_parser_declares_only_class_p
> > > (cp_parser *);
> > > static void cp_parser_set_storage_class
> > > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > > case RID_OFFSETOF:
> > > return cp_parser_builtin_offsetof (parser);
> > >
> > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > - case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_EXPR
> > > - return cp_parser_trait (parser, token->keyword);
> > > -
> > > // C++ concepts
> > > case RID_REQUIRES:
> > > return cp_parser_requires_expression (parser);
> > > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > > `::' as the beginning of a qualified-id, or the "operator"
> > > keyword. */
> > > case CPP_NAME:
> > > + {
> > > + const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > + if (trait)
> > > + return cp_parser_trait (parser, trait);
> > > + }
> > > + /* FALLTHRU */
> > > case CPP_SCOPE:
> > > case CPP_TEMPLATE_ID:
> > > case CPP_NESTED_NAME_SPECIFIER:
> > > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > > /* Parse a builtin trait expression or type. */
> > >
> > > static cp_expr
> > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > > {
> > > - cp_trait_kind kind;
> > > tree type1, type2 = NULL_TREE;
> > > - bool binary = false;
> > > - bool variadic = false;
> > > - bool type = false;
> > > -
> > > - switch (keyword)
> > > - {
> > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > - case RID_##CODE: \
> > > - kind = CPTK_##CODE; \
> > > - binary = (ARITY == 2); \
> > > - variadic = (ARITY == -1); \
> > > - type = (TCC == tcc_type); \
> > > - break;
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT
> > > - default:
> > > - gcc_unreachable ();
> > > - }
> > > + const bool binary = (trait->arity == 2);
> > > + const bool variadic = (trait->arity == -1);
> > >
> > > /* Get location of initial token. */
> > > location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > cp_lexer_consume_token (parser->lexer);
> > >
> > > matching_parens parens;
> > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > cp_parser_require (parser, CPP_LESS, RT_LESS);
> > > else
> > > parens.require_open (parser);
> > >
> > > - if (kind == CPTK_IS_DEDUCIBLE)
> > > + if (trait->kind == CPTK_IS_DEDUCIBLE)
> > > {
> > > const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > > type1 = cp_parser_id_expression (parser,
> > > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > /*optional_p=*/false);
> > > type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > > }
> > > - else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > + else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > /* __type_pack_element takes an expression as its first argument and uses
> > > template-id syntax instead of function call syntax (for consistency
> > > with Clang). We special case these properties of __type_pack_element
> > > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > if (type1 == error_mark_node)
> > > return error_mark_node;
> > >
> > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > {
> > > cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > > tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > }
> > >
> > > location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > /* cp_parser_enclosed_template_argument_list above already took care
> > > of parsing the closing '>'. */;
> > > else
> > > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > >
> > > /* Complete the trait expression, which may mean either processing
> > > the trait expr now or saving it for template instantiation. */
> > > - switch (kind)
> > > + switch (trait->kind)
> > > {
> > > case CPTK_BASES:
> > > return cp_expr (finish_bases (type1, false), trait_loc);
> > > case CPTK_DIRECT_BASES:
> > > return cp_expr (finish_bases (type1, true), trait_loc);
> > > default:
> > > - if (type)
> > > - return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > + if (trait->type)
> > > + return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > > else
> > > - return finish_trait_expr (trait_loc, kind, type1, type2);
> > > + return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > > }
> > > }
> > >
> > > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > >
> > > return type;
> > >
> > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > - case RID_##CODE:
> > > -#include "cp-trait.def"
> > > -#undef DEFTRAIT_TYPE
> > > - type = cp_parser_trait (parser, token->keyword);
> > > + default:
> > > + break;
> > > + }
> > > +
> > > + /* If token is a type-yielding built-in traits, parse it. */
> > > + const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > + if (trait)
> > > + {
> > > + type = cp_parser_trait (parser, trait);
> > > if (decl_specs)
> > > cp_parser_set_decl_spec_type (decl_specs, type,
> > > token,
> > > /*type_definition_p=*/false);
> > >
> > > return type;
> > > -
> > > - default:
> > > - break;
> > > }
> > >
> > > /* If token is an already-parsed decltype not followed by ::,
> > > --
> > > 2.42.0
> > >
> > >
> >
>
>
On Sun, Oct 15, 2023 at 2:50 PM Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sun, 15 Oct 2023, Ken Matsui wrote:
>
> > On Sun, Oct 15, 2023 at 1:43 PM Patrick Palka <ppalka@redhat.com> wrote:
> > >
> > > On Fri, 13 Oct 2023, Ken Matsui wrote:
> > >
> > > > Since RID_MAX soon reaches 255 and all built-in traits are used approximately
> > > > once in a C++ translation unit, this patch removes all RID values for built-in
> > > > traits and uses gperf to look up the specific trait. Rather than holding
> > > > traits as keywords, we set all trait identifiers as cik_trait, which is a new
> > > > cp_identifier_kind. As cik_reserved_for_udlit was unused and
> > > > cp_identifier_kind is 3 bits, we replaced the unused field with the new
> > > > cik_trait. Also, the later patch handles a subsequent token to the built-in
> > > > identifier so that we accept the use of non-function-like built-in trait
> > > > identifiers.
> > >
> > > Awesome! It's great we won't have to rename any existing identifiers in
> > > libstdc++ with this approach.
> > >
> > > I think this patch looks perfect, assuming we want to stick with the gperf
> > > approach, but I just noticed that IDENTIFIER nodes have an IDENTIFIER_CP_INDEX
> > > field which is currently only used for operator name identifiers to
> > > optimize looking up operator information. Could we reuse this field for
> > > IDENTIFIER_TRAIT_P identifiers as well in order to store their
> > > corresponding cp_trait_kind? If so then I think we wouldn't need to use
> > > gperf for the built-in traits at all, since the mapping from identifier
> > > to cp_trait_kind would be implicit in each IDENTIFIER node, which would
> > > perhaps be a nice simplification (and just as fast if not faster than gperf)?
> > >
> >
> > Thank you! I think this way decreases the size of the compiler even if
> > we do not see speed improvements. Since IDENTIFIER_CP_INDEX
> > (base.u.bits.address_space) is an unsigned char (addr_space_t), we can
> > have only up to 255 traits. Is this acceptable?
>
> Good points. Given there's so far around 150 standard library traits, a
> limit of 255 should last us quite a while so IMHO it's acceptable :)
>
Sounds great! I will update the patch in this way. Thank you!
> >
> > > >
> > > > gcc/c-family/ChangeLog:
> > > >
> > > > * c-common.cc (c_common_reswords): Remove all mappings of
> > > > built-in traits.
> > > > * c-common.h (enum rid): Remove all RID values for built-in traits.
> > > >
> > > > gcc/cp/ChangeLog:
> > > >
> > > > * Make-lang.in: Add targets to generate cp-trait.gperf and
> > > > cp-trait.h.
> > > > * cp-objcp-common.cc (names_builtin_p): Remove all RID value
> > > > cases for built-in traits. Check for built-in traits via
> > > > the new cik_trait identifier.
> > > > * cp-tree.h (cik_reserved_for_udlit): Rename to ...
> > > > (cik_trait): ... this.
> > > > (IDENTIFIER_ANY_OP_P): Exclude cik_trait.
> > > > (IDENTIFIER_TRAIT_P): New macro to detect cik_trait.
> > > > * lex.cc (init_cp_traits): New function to set cik_trait for all
> > > > built-in trait identifiers.
> > > > (cxx_init): Call init_cp_traits function.
> > > > * parser.cc (cp_lexer_lookup_trait): New function to look up a
> > > > built-in trait from a token by gperf.
> > > > (cp_lexer_lookup_trait_expr): Likewise, look up an
> > > > expression-yielding built-in trait.
> > > > (cp_lexer_lookup_trait_type): Likewise, look up a type-yielding
> > > > built-in trait.
> > > > (cp_keyword_starts_decl_specifier_p): Remove all RID value cases
> > > > for built-in traits.
> > > > (cp_lexer_next_token_is_decl_specifier_keyword): Handle
> > > > type-yielding built-in traits.
> > > > (cp_parser_primary_expression): Remove all RID value cases for
> > > > built-in traits. Handle expression-yielding built-in traits.
> > > > (cp_parser_trait): Handle cp_trait instead of enum rid.
> > > > (cp_parser_simple_type_specifier): Remove all RID value cases
> > > > for built-in traits. Handle type-yielding built-in traits.
> > > > * cp-trait-head.in: New file.
> > > > * cp-trait.gperf: New file.
> > > > * cp-trait.h: New file.
> > > >
> > > > Co-authored-by: Patrick Palka <ppalka@redhat.com>
> > > > Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
> > > > ---
> > > > gcc/c-family/c-common.cc | 7 --
> > > > gcc/c-family/c-common.h | 5 -
> > > > gcc/cp/Make-lang.in | 26 ++++
> > > > gcc/cp/cp-objcp-common.cc | 8 +-
> > > > gcc/cp/cp-trait-head.in | 30 +++++
> > > > gcc/cp/cp-trait.gperf | 74 ++++++++++++
> > > > gcc/cp/cp-trait.h | 247 ++++++++++++++++++++++++++++++++++++++
> > > > gcc/cp/cp-tree.h | 14 ++-
> > > > gcc/cp/lex.cc | 19 +++
> > > > gcc/cp/parser.cc | 132 ++++++++++++--------
> > > > 10 files changed, 492 insertions(+), 70 deletions(-)
> > > > create mode 100644 gcc/cp/cp-trait-head.in
> > > > create mode 100644 gcc/cp/cp-trait.gperf
> > > > create mode 100644 gcc/cp/cp-trait.h
> > > >
> > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > > index f044db5b797..21fd333ef57 100644
> > > > --- a/gcc/c-family/c-common.cc
> > > > +++ b/gcc/c-family/c-common.cc
> > > > @@ -508,13 +508,6 @@ const struct c_common_resword c_common_reswords[] =
> > > > { "wchar_t", RID_WCHAR, D_CXXONLY },
> > > > { "while", RID_WHILE, 0 },
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > - { NAME, RID_##CODE, D_CXXONLY },
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > - /* An alias for __is_same. */
> > > > - { "__is_same_as", RID_IS_SAME, D_CXXONLY },
> > > > -
> > > > /* C++ transactional memory. */
> > > > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
> > > > { "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
> > > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > > index 1fdba7ef3ea..051a442e0f4 100644
> > > > --- a/gcc/c-family/c-common.h
> > > > +++ b/gcc/c-family/c-common.h
> > > > @@ -168,11 +168,6 @@ enum rid
> > > > RID_BUILTIN_LAUNDER,
> > > > RID_BUILTIN_BIT_CAST,
> > > >
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > - RID_##CODE,
> > > > -#include "cp/cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > -
> > > > /* C++11 */
> > > > RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
> > > >
> > > > diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
> > > > index 2727fb7f8cc..a67d1c3e9f3 100644
> > > > --- a/gcc/cp/Make-lang.in
> > > > +++ b/gcc/cp/Make-lang.in
> > > > @@ -34,6 +34,8 @@
> > > > # - the compiler proper (eg: cc1plus)
> > > > # - define the names for selecting the language in LANGUAGES.
> > > >
> > > > +AWK = @AWK@
> > > > +
> > > > # Actual names to use when installing a native compiler.
> > > > CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
> > > > GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
> > > > @@ -186,6 +188,30 @@ endif
> > > > # This is the file that depends on the generated header file.
> > > > cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
> > > >
> > > > +# We always need the dependency on the .gperf file
> > > > +# because it itself is generated.
> > > > +ifeq ($(ENABLE_MAINTAINER_RULES), true)
> > > > +$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
> > > > +else
> > > > +$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
> > > > +endif
> > > > + gperf -o -C -E -k '8' -D -N 'find' -L C++ \
> > > > + $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
> > > > +
> > > > +# The cp-trait.gperf file itself is generated from
> > > > +# cp-trait-head.in and cp-trait.def files.
> > > > +$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
> > > > + cat $< > $@
> > > > + $(AWK) -F', *' '/^DEFTRAIT_/ { \
> > > > + type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
> > > > + gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
> > > > + gsub(/\)/, "", $$3); \
> > > > + print $$2", CPTK_" $$1", "$$3", "type; \
> > > > + }' $(srcdir)/cp/cp-trait.def >> $@
> > > > +
> > > > +# This is the file that depends on the generated header file.
> > > > +cp/parser.o: $(srcdir)/cp/cp-trait.h
> > > > +
> > > > components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
> > > > components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
> > > >
> > > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> > > > index 93b027b80ce..b1adacfec07 100644
> > > > --- a/gcc/cp/cp-objcp-common.cc
> > > > +++ b/gcc/cp/cp-objcp-common.cc
> > > > @@ -421,6 +421,10 @@ names_builtin_p (const char *name)
> > > > }
> > > > }
> > > >
> > > > + /* Check for built-in traits. */
> > > > + if (IDENTIFIER_TRAIT_P (id))
> > > > + return true;
> > > > +
> > > > /* Also detect common reserved C++ words that aren't strictly built-in
> > > > functions. */
> > > > switch (C_RID_CODE (id))
> > > > @@ -434,10 +438,6 @@ names_builtin_p (const char *name)
> > > > case RID_BUILTIN_ASSOC_BARRIER:
> > > > case RID_BUILTIN_BIT_CAST:
> > > > case RID_OFFSETOF:
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > - case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > return true;
> > > > default:
> > > > break;
> > > > diff --git a/gcc/cp/cp-trait-head.in b/gcc/cp/cp-trait-head.in
> > > > new file mode 100644
> > > > index 00000000000..9357eea1238
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait-head.in
> > > > @@ -0,0 +1,30 @@
> > > > +%language=C++
> > > > +%define class-name cp_trait_lookup
> > > > +%struct-type
> > > > +%{
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3. If not see
> > > > +<http://www.gnu.org/licenses/>. */
> > > > +%}
> > > > +struct cp_trait {
> > > > + const char *name;
> > > > + enum cp_trait_kind kind;
> > > > + short arity;
> > > > + bool type;
> > > > +};
> > > > +%%
> > > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > > diff --git a/gcc/cp/cp-trait.gperf b/gcc/cp/cp-trait.gperf
> > > > new file mode 100644
> > > > index 00000000000..47e3c1af499
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait.gperf
> > > > @@ -0,0 +1,74 @@
> > > > +%language=C++
> > > > +%define class-name cp_trait_lookup
> > > > +%struct-type
> > > > +%{
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3. If not see
> > > > +<http://www.gnu.org/licenses/>. */
> > > > +%}
> > > > +struct cp_trait {
> > > > + const char *name;
> > > > + enum cp_trait_kind kind;
> > > > + short arity;
> > > > + bool type;
> > > > +};
> > > > +%%
> > > > +"__is_same_as", CPTK_IS_SAME, 2, false
> > > > +"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
> > > > +"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
> > > > +"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
> > > > +"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
> > > > +"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
> > > > +"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
> > > > +"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
> > > > +"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
> > > > +"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
> > > > +"__is_abstract", CPTK_IS_ABSTRACT, 1, false
> > > > +"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
> > > > +"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
> > > > +"__is_base_of", CPTK_IS_BASE_OF, 2, false
> > > > +"__is_class", CPTK_IS_CLASS, 1, false
> > > > +"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
> > > > +"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
> > > > +"__is_empty", CPTK_IS_EMPTY, 1, false
> > > > +"__is_enum", CPTK_IS_ENUM, 1, false
> > > > +"__is_final", CPTK_IS_FINAL, 1, false
> > > > +"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
> > > > +"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
> > > > +"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
> > > > +"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
> > > > +"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
> > > > +"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
> > > > +"__is_pod", CPTK_IS_POD, 1, false
> > > > +"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
> > > > +"__is_same", CPTK_IS_SAME, 2, false
> > > > +"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
> > > > +"__is_trivial", CPTK_IS_TRIVIAL, 1, false
> > > > +"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
> > > > +"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
> > > > +"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
> > > > +"__is_union", CPTK_IS_UNION, 1, false
> > > > +"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
> > > > +"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
> > > > +"__remove_cv", CPTK_REMOVE_CV, 1, true
> > > > +"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
> > > > +"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
> > > > +"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
> > > > +"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
> > > > +"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
> > > > +"__bases", CPTK_BASES, 1, true
> > > > +"__direct_bases", CPTK_DIRECT_BASES, 1, true
> > > > diff --git a/gcc/cp/cp-trait.h b/gcc/cp/cp-trait.h
> > > > new file mode 100644
> > > > index 00000000000..97ba8492d15
> > > > --- /dev/null
> > > > +++ b/gcc/cp/cp-trait.h
> > > > @@ -0,0 +1,247 @@
> > > > +/* C++ code produced by gperf version 3.1 */
> > > > +/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf */
> > > > +
> > > > +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
> > > > + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
> > > > + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
> > > > + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
> > > > + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
> > > > + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
> > > > + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
> > > > + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
> > > > + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
> > > > + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
> > > > + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
> > > > + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
> > > > + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
> > > > + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
> > > > + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
> > > > + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
> > > > + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
> > > > + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
> > > > + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
> > > > + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
> > > > + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
> > > > + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
> > > > + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
> > > > +/* The character set is not based on ISO-646. */
> > > > +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
> > > > +#endif
> > > > +
> > > > +#line 4 "../../gcc/cp/cp-trait.gperf"
> > > > +
> > > > +/* Copyright (C) 2023 Free Software Foundation, Inc.
> > > > +
> > > > +This file is part of GCC.
> > > > +
> > > > +GCC is free software; you can redistribute it and/or modify it under
> > > > +the terms of the GNU General Public License as published by the Free
> > > > +Software Foundation; either version 3, or (at your option) any later
> > > > +version.
> > > > +
> > > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> > > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> > > > +for more details.
> > > > +
> > > > +You should have received a copy of the GNU General Public License
> > > > +along with GCC; see the file COPYING3. If not see
> > > > +<http://www.gnu.org/licenses/>. */
> > > > +#line 23 "../../gcc/cp/cp-trait.gperf"
> > > > +struct cp_trait {
> > > > + const char *name;
> > > > + enum cp_trait_kind kind;
> > > > + short arity;
> > > > + bool type;
> > > > +};
> > > > +/* maximum key range = 79, duplicates = 0 */
> > > > +
> > > > +class cp_trait_lookup
> > > > +{
> > > > +private:
> > > > + static inline unsigned int hash (const char *str, size_t len);
> > > > +public:
> > > > + static const struct cp_trait *find (const char *str, size_t len);
> > > > +};
> > > > +
> > > > +inline unsigned int
> > > > +cp_trait_lookup::hash (const char *str, size_t len)
> > > > +{
> > > > + static const unsigned char asso_values[] =
> > > > + {
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 1, 86, 86,
> > > > + 0, 35, 86, 0, 86, 0, 86, 86, 10, 10,
> > > > + 50, 15, 55, 86, 30, 5, 15, 0, 86, 86,
> > > > + 86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
> > > > + 86, 86, 86, 86, 86, 86
> > > > + };
> > > > + unsigned int hval = len;
> > > > +
> > > > + switch (hval)
> > > > + {
> > > > + default:
> > > > + hval += asso_values[static_cast<unsigned char>(str[7])];
> > > > + /*FALLTHROUGH*/
> > > > + case 7:
> > > > + break;
> > > > + }
> > > > + return hval;
> > > > +}
> > > > +
> > > > +const struct cp_trait *
> > > > +cp_trait_lookup::find (const char *str, size_t len)
> > > > +{
> > > > + enum
> > > > + {
> > > > + TOTAL_KEYWORDS = 45,
> > > > + MIN_WORD_LENGTH = 7,
> > > > + MAX_WORD_LENGTH = 37,
> > > > + MIN_HASH_VALUE = 7,
> > > > + MAX_HASH_VALUE = 85
> > > > + };
> > > > +
> > > > + static const struct cp_trait wordlist[] =
> > > > + {
> > > > +#line 73 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__bases", CPTK_BASES, 1, true},
> > > > +#line 56 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_pod", CPTK_IS_POD, 1, false},
> > > > +#line 48 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_enum", CPTK_IS_ENUM, 1, false},
> > > > +#line 64 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_union", CPTK_IS_UNION, 1, false},
> > > > +#line 44 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_class", CPTK_IS_CLASS, 1, false},
> > > > +#line 60 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
> > > > +#line 41 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
> > > > +#line 72 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
> > > > +#line 43 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
> > > > +#line 40 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
> > > > +#line 58 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_same", CPTK_IS_SAME, 2, false},
> > > > +#line 42 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
> > > > +#line 59 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
> > > > +#line 30 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_same_as", CPTK_IS_SAME, 2, false},
> > > > +#line 63 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
> > > > +#line 39 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
> > > > +#line 61 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
> > > > +#line 57 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
> > > > +#line 71 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
> > > > +#line 62 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
> > > > +#line 74 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
> > > > +#line 51 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
> > > > +#line 33 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
> > > > +#line 31 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
> > > > +#line 55 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
> > > > +#line 52 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
> > > > +#line 54 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
> > > > +#line 32 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
> > > > +#line 53 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
> > > > +#line 50 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
> > > > +#line 67 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__remove_cv", CPTK_REMOVE_CV, 1, true},
> > > > +#line 36 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
> > > > +#line 68 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
> > > > +#line 34 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
> > > > +#line 69 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
> > > > +#line 37 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
> > > > +#line 35 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
> > > > +#line 49 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_final", CPTK_IS_FINAL, 1, false},
> > > > +#line 47 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_empty", CPTK_IS_EMPTY, 1, false},
> > > > +#line 46 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
> > > > +#line 45 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
> > > > +#line 66 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
> > > > +#line 65 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
> > > > +#line 70 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
> > > > +#line 38 "../../gcc/cp/cp-trait.gperf"
> > > > + {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
> > > > + };
> > > > +
> > > > + static const signed char lookup[] =
> > > > + {
> > > > + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, -1,
> > > > + 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
> > > > + 19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
> > > > + 29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
> > > > + -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
> > > > + 41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> > > > + -1, 44
> > > > + };
> > > > +
> > > > + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
> > > > + {
> > > > + unsigned int key = hash (str, len);
> > > > +
> > > > + if (key <= MAX_HASH_VALUE)
> > > > + {
> > > > + int index = lookup[key];
> > > > +
> > > > + if (index >= 0)
> > > > + {
> > > > + const char *s = wordlist[index].name;
> > > > +
> > > > + if (*str == *s && !strcmp (str + 1, s + 1))
> > > > + return &wordlist[index];
> > > > + }
> > > > + }
> > > > + }
> > > > + return 0;
> > > > +}
> > > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > > index 6e34952da99..62e134886fb 100644
> > > > --- a/gcc/cp/cp-tree.h
> > > > +++ b/gcc/cp/cp-tree.h
> > > > @@ -1226,7 +1226,7 @@ enum cp_identifier_kind {
> > > > cik_simple_op = 4, /* Non-assignment operator name. */
> > > > cik_assign_op = 5, /* An assignment operator name. */
> > > > cik_conv_op = 6, /* Conversion operator name. */
> > > > - cik_reserved_for_udlit = 7, /* Not yet in use */
> > > > + cik_trait = 7, /* Built-in trait name. */
> > > > cik_max
> > > > };
> > > >
> > > > @@ -1271,9 +1271,9 @@ enum cp_identifier_kind {
> > > > & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > > /* True if this identifier is for any operator name (including
> > > > - conversions). Value 4, 5, 6 or 7. */
> > > > + conversions). Value 4, 5, or 6. */
> > > > #define IDENTIFIER_ANY_OP_P(NODE) \
> > > > - (IDENTIFIER_KIND_BIT_2 (NODE))
> > > > + (IDENTIFIER_KIND_BIT_2 (NODE) && !IDENTIFIER_TRAIT_P (NODE))
> > > >
> > > > /* True if this identifier is for an overloaded operator. Values 4, 5. */
> > > > #define IDENTIFIER_OVL_OP_P(NODE) \
> > > > @@ -1286,12 +1286,18 @@ enum cp_identifier_kind {
> > > > & IDENTIFIER_KIND_BIT_0 (NODE))
> > > >
> > > > /* True if this identifier is the name of a type-conversion
> > > > - operator. Value 7. */
> > > > + operator. Value 6. */
> > > > #define IDENTIFIER_CONV_OP_P(NODE) \
> > > > (IDENTIFIER_ANY_OP_P (NODE) \
> > > > & IDENTIFIER_KIND_BIT_1 (NODE) \
> > > > & (!IDENTIFIER_KIND_BIT_0 (NODE)))
> > > >
> > > > +/* True if this identifier is the name of a built-in trait. */
> > > > +#define IDENTIFIER_TRAIT_P(NODE) \
> > > > + (IDENTIFIER_KIND_BIT_0 (NODE) \
> > > > + && IDENTIFIER_KIND_BIT_1 (NODE) \
> > > > + && IDENTIFIER_KIND_BIT_2 (NODE))
> > > > +
> > > > /* True if this identifier is a new or delete operator. */
> > > > #define IDENTIFIER_NEWDEL_OP_P(NODE) \
> > > > (IDENTIFIER_OVL_OP_P (NODE) \
> > > > diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
> > > > index 64bcfb18196..f6e1f6a4075 100644
> > > > --- a/gcc/cp/lex.cc
> > > > +++ b/gcc/cp/lex.cc
> > > > @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
> > > > #include "langhooks.h"
> > > >
> > > > static int interface_strcmp (const char *);
> > > > +static void init_cp_traits (void);
> > > > static void init_cp_pragma (void);
> > > >
> > > > static tree parse_strconst_pragma (const char *, int);
> > > > @@ -283,6 +284,23 @@ init_reswords (void)
> > > > }
> > > > }
> > > >
> > > > +/* Initialize the C++ traits. */
> > > > +static void
> > > > +init_cp_traits (void)
> > > > +{
> > > > + tree id;
> > > > +
> > > > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > + id = get_identifier (NAME); \
> > > > + set_identifier_kind (id, cik_trait);
> > > > +#include "cp/cp-trait.def"
> > > > +#undef DEFTRAIT
> > > > +
> > > > + /* An alias for __is_same. */
> > > > + id = get_identifier ("__is_same_as");
> > > > + set_identifier_kind (id, cik_trait);
> > > > +}
> > > > +
> > > > static void
> > > > init_cp_pragma (void)
> > > > {
> > > > @@ -324,6 +342,7 @@ cxx_init (void)
> > > > input_location = BUILTINS_LOCATION;
> > > >
> > > > init_reswords ();
> > > > + init_cp_traits ();
> > > > init_tree ();
> > > > init_cp_semantics ();
> > > > init_operators ();
> > > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > > > index f3abae716fe..39952893ffa 100644
> > > > --- a/gcc/cp/parser.cc
> > > > +++ b/gcc/cp/parser.cc
> > > > @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
> > > > #include "contracts.h"
> > > > #include "bitmap.h"
> > > > #include "builtins.h"
> > > > +#include "cp-trait.h"
> > > >
> > > >
> > > > /* The lexer. */
> > > > @@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
> > > > (cp_lexer *) ATTRIBUTE_UNUSED;
> > > > static void cp_lexer_stop_debugging
> > > > (cp_lexer *) ATTRIBUTE_UNUSED;
> > > > +static const cp_trait *cp_lexer_lookup_trait
> > > > + (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_expr
> > > > + (const cp_token *);
> > > > +static const cp_trait *cp_lexer_lookup_trait_type
> > > > + (const cp_token *);
> > > >
> > > > static cp_token_cache *cp_token_cache_new
> > > > (cp_token *, cp_token *);
> > > > @@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > > case RID_CONSTEVAL:
> > > > return true;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > - case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > - return true;
> > > > -
> > > > default:
> > > > if (keyword >= RID_FIRST_INT_N
> > > > && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
> > > > @@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
> > > > }
> > > > }
> > > >
> > > > +/* Look ups the corresponding built-in trait if a given token is
> > > > + a built-in trait. Otherwise, returns nullptr. */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait (const cp_token *token)
> > > > +{
> > > > + tree id = token->u.value;
> > > > +
> > > > + if (token->type == CPP_NAME
> > > > + && TREE_CODE (id) == IDENTIFIER_NODE
> > > > + && IDENTIFIER_TRAIT_P (id))
> > > > + {
> > > > + const char *id_str = IDENTIFIER_POINTER (id);
> > > > + const int id_len = IDENTIFIER_LENGTH (id);
> > > > + return cp_trait_lookup::find (id_str, id_len);
> > > > + }
> > > > + return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is an expression-yielding
> > > > + built-in trait. */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_expr (const cp_token *token)
> > > > +{
> > > > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > + if (trait && !trait->type)
> > > > + return trait;
> > > > +
> > > > + return nullptr;
> > > > +}
> > > > +
> > > > +/* Similarly, but only if the token is a type-yielding
> > > > + built-in trait. */
> > > > +
> > > > +static const cp_trait *
> > > > +cp_lexer_lookup_trait_type (const cp_token *token)
> > > > +{
> > > > + const cp_trait *trait = cp_lexer_lookup_trait (token);
> > > > + if (trait && trait->type)
> > > > + return trait;
> > > > +
> > > > + return nullptr;
> > > > +}
> > > > +
> > > > /* Return true if the next token is a keyword for a decl-specifier. */
> > > >
> > > > static bool
> > > > @@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
> > > > cp_token *token;
> > > >
> > > > token = cp_lexer_peek_token (lexer);
> > > > + if (cp_lexer_lookup_trait_type (token))
> > > > + return true;
> > > > return cp_keyword_starts_decl_specifier_p (token->keyword);
> > > > }
> > > >
> > > > @@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
> > > > static tree cp_parser_sizeof_operand
> > > > (cp_parser *, enum rid);
> > > > static cp_expr cp_parser_trait
> > > > - (cp_parser *, enum rid);
> > > > + (cp_parser *, const cp_trait *);
> > > > static bool cp_parser_declares_only_class_p
> > > > (cp_parser *);
> > > > static void cp_parser_set_storage_class
> > > > @@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
> > > > case RID_OFFSETOF:
> > > > return cp_parser_builtin_offsetof (parser);
> > > >
> > > > -#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
> > > > - case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_EXPR
> > > > - return cp_parser_trait (parser, token->keyword);
> > > > -
> > > > // C++ concepts
> > > > case RID_REQUIRES:
> > > > return cp_parser_requires_expression (parser);
> > > > @@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
> > > > `::' as the beginning of a qualified-id, or the "operator"
> > > > keyword. */
> > > > case CPP_NAME:
> > > > + {
> > > > + const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
> > > > + if (trait)
> > > > + return cp_parser_trait (parser, trait);
> > > > + }
> > > > + /* FALLTHRU */
> > > > case CPP_SCOPE:
> > > > case CPP_TEMPLATE_ID:
> > > > case CPP_NESTED_NAME_SPECIFIER:
> > > > @@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> > > > /* Parse a builtin trait expression or type. */
> > > >
> > > > static cp_expr
> > > > -cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > +cp_parser_trait (cp_parser* parser, const cp_trait* trait)
> > > > {
> > > > - cp_trait_kind kind;
> > > > tree type1, type2 = NULL_TREE;
> > > > - bool binary = false;
> > > > - bool variadic = false;
> > > > - bool type = false;
> > > > -
> > > > - switch (keyword)
> > > > - {
> > > > -#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
> > > > - case RID_##CODE: \
> > > > - kind = CPTK_##CODE; \
> > > > - binary = (ARITY == 2); \
> > > > - variadic = (ARITY == -1); \
> > > > - type = (TCC == tcc_type); \
> > > > - break;
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT
> > > > - default:
> > > > - gcc_unreachable ();
> > > > - }
> > > > + const bool binary = (trait->arity == 2);
> > > > + const bool variadic = (trait->arity == -1);
> > > >
> > > > /* Get location of initial token. */
> > > > location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > @@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > cp_lexer_consume_token (parser->lexer);
> > > >
> > > > matching_parens parens;
> > > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > > cp_parser_require (parser, CPP_LESS, RT_LESS);
> > > > else
> > > > parens.require_open (parser);
> > > >
> > > > - if (kind == CPTK_IS_DEDUCIBLE)
> > > > + if (trait->kind == CPTK_IS_DEDUCIBLE)
> > > > {
> > > > const cp_token* token = cp_lexer_peek_token (parser->lexer);
> > > > type1 = cp_parser_id_expression (parser,
> > > > @@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > /*optional_p=*/false);
> > > > type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
> > > > }
> > > > - else if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > + else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > > /* __type_pack_element takes an expression as its first argument and uses
> > > > template-id syntax instead of function call syntax (for consistency
> > > > with Clang). We special case these properties of __type_pack_element
> > > > @@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > if (type1 == error_mark_node)
> > > > return error_mark_node;
> > > >
> > > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > > {
> > > > cp_parser_require (parser, CPP_COMMA, RT_COMMA);
> > > > tree trailing = cp_parser_enclosed_template_argument_list (parser);
> > > > @@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > > }
> > > >
> > > > location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
> > > > - if (kind == CPTK_TYPE_PACK_ELEMENT)
> > > > + if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
> > > > /* cp_parser_enclosed_template_argument_list above already took care
> > > > of parsing the closing '>'. */;
> > > > else
> > > > @@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
> > > >
> > > > /* Complete the trait expression, which may mean either processing
> > > > the trait expr now or saving it for template instantiation. */
> > > > - switch (kind)
> > > > + switch (trait->kind)
> > > > {
> > > > case CPTK_BASES:
> > > > return cp_expr (finish_bases (type1, false), trait_loc);
> > > > case CPTK_DIRECT_BASES:
> > > > return cp_expr (finish_bases (type1, true), trait_loc);
> > > > default:
> > > > - if (type)
> > > > - return finish_trait_type (kind, type1, type2, tf_warning_or_error);
> > > > + if (trait->type)
> > > > + return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
> > > > else
> > > > - return finish_trait_expr (trait_loc, kind, type1, type2);
> > > > + return finish_trait_expr (trait_loc, trait->kind, type1, type2);
> > > > }
> > > > }
> > > >
> > > > @@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> > > >
> > > > return type;
> > > >
> > > > -#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
> > > > - case RID_##CODE:
> > > > -#include "cp-trait.def"
> > > > -#undef DEFTRAIT_TYPE
> > > > - type = cp_parser_trait (parser, token->keyword);
> > > > + default:
> > > > + break;
> > > > + }
> > > > +
> > > > + /* If token is a type-yielding built-in traits, parse it. */
> > > > + const cp_trait* trait = cp_lexer_lookup_trait_type (token);
> > > > + if (trait)
> > > > + {
> > > > + type = cp_parser_trait (parser, trait);
> > > > if (decl_specs)
> > > > cp_parser_set_decl_spec_type (decl_specs, type,
> > > > token,
> > > > /*type_definition_p=*/false);
> > > >
> > > > return type;
> > > > -
> > > > - default:
> > > > - break;
> > > > }
> > > >
> > > > /* If token is an already-parsed decltype not followed by ::,
> > > > --
> > > > 2.42.0
> > > >
> > > >
> > >
> >
> >
@@ -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,
@@ -34,6 +34,8 @@
# - the compiler proper (eg: cc1plus)
# - define the names for selecting the language in LANGUAGES.
+AWK = @AWK@
+
# Actual names to use when installing a native compiler.
CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
@@ -186,6 +188,30 @@ endif
# This is the file that depends on the generated header file.
cp/name-lookup.o: $(srcdir)/cp/std-name-hint.h
+# We always need the dependency on the .gperf file
+# because it itself is generated.
+ifeq ($(ENABLE_MAINTAINER_RULES), true)
+$(srcdir)/cp/cp-trait.h: $(srcdir)/cp/cp-trait.gperf
+else
+$(srcdir)/cp/cp-trait.h: | $(srcdir)/cp/cp-trait.gperf
+endif
+ gperf -o -C -E -k '8' -D -N 'find' -L C++ \
+ $(srcdir)/cp/cp-trait.gperf --output-file $(srcdir)/cp/cp-trait.h
+
+# The cp-trait.gperf file itself is generated from
+# cp-trait-head.in and cp-trait.def files.
+$(srcdir)/cp/cp-trait.gperf: $(srcdir)/cp/cp-trait-head.in $(srcdir)/cp/cp-trait.def
+ cat $< > $@
+ $(AWK) -F', *' '/^DEFTRAIT_/ { \
+ type = (index($$1, "DEFTRAIT_TYPE") != 0 ? "true" : "false"); \
+ gsub(/DEFTRAIT_(EXPR|TYPE) \(/, "", $$1); \
+ gsub(/\)/, "", $$3); \
+ print $$2", CPTK_" $$1", "$$3", "type; \
+ }' $(srcdir)/cp/cp-trait.def >> $@
+
+# This is the file that depends on the generated header file.
+cp/parser.o: $(srcdir)/cp/cp-trait.h
+
components_in_prev = "bfd opcodes binutils fixincludes gas gcc gmp mpfr mpc isl gold intl ld libbacktrace libcpp libcody libdecnumber libiberty libiberty-linker-plugin libiconv zlib lto-plugin libctf libsframe"
components_in_prev_target = "libstdc++-v3 libsanitizer libvtv libgcc libbacktrace libphobos zlib libgomp libatomic"
@@ -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;
new file mode 100644
@@ -0,0 +1,30 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+%}
+struct cp_trait {
+ const char *name;
+ enum cp_trait_kind kind;
+ short arity;
+ bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
new file mode 100644
@@ -0,0 +1,74 @@
+%language=C++
+%define class-name cp_trait_lookup
+%struct-type
+%{
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+%}
+struct cp_trait {
+ const char *name;
+ enum cp_trait_kind kind;
+ short arity;
+ bool type;
+};
+%%
+"__is_same_as", CPTK_IS_SAME, 2, false
+"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false
+"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false
+"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false
+"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false
+"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false
+"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false
+"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false
+"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false
+"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false
+"__is_abstract", CPTK_IS_ABSTRACT, 1, false
+"__is_aggregate", CPTK_IS_AGGREGATE, 1, false
+"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false
+"__is_base_of", CPTK_IS_BASE_OF, 2, false
+"__is_class", CPTK_IS_CLASS, 1, false
+"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false
+"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false
+"__is_empty", CPTK_IS_EMPTY, 1, false
+"__is_enum", CPTK_IS_ENUM, 1, false
+"__is_final", CPTK_IS_FINAL, 1, false
+"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false
+"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false
+"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false
+"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false
+"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false
+"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false
+"__is_pod", CPTK_IS_POD, 1, false
+"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false
+"__is_same", CPTK_IS_SAME, 2, false
+"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false
+"__is_trivial", CPTK_IS_TRIVIAL, 1, false
+"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false
+"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false
+"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false
+"__is_union", CPTK_IS_UNION, 1, false
+"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false
+"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false
+"__remove_cv", CPTK_REMOVE_CV, 1, true
+"__remove_cvref", CPTK_REMOVE_CVREF, 1, true
+"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true
+"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true
+"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true
+"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false
+"__bases", CPTK_BASES, 1, true
+"__direct_bases", CPTK_DIRECT_BASES, 1, true
new file mode 100644
@@ -0,0 +1,247 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -o -C -E -k 8 -D -N find -L C++ --output-file ../../gcc/cp/cp-trait.h ../../gcc/cp/cp-trait.gperf */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 4 "../../gcc/cp/cp-trait.gperf"
+
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+#line 23 "../../gcc/cp/cp-trait.gperf"
+struct cp_trait {
+ const char *name;
+ enum cp_trait_kind kind;
+ short arity;
+ bool type;
+};
+/* maximum key range = 79, duplicates = 0 */
+
+class cp_trait_lookup
+{
+private:
+ static inline unsigned int hash (const char *str, size_t len);
+public:
+ static const struct cp_trait *find (const char *str, size_t len);
+};
+
+inline unsigned int
+cp_trait_lookup::hash (const char *str, size_t len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 1, 86, 86,
+ 0, 35, 86, 0, 86, 0, 86, 86, 10, 10,
+ 50, 15, 55, 86, 30, 5, 15, 0, 86, 86,
+ 86, 20, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86
+ };
+ unsigned int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[static_cast<unsigned char>(str[7])];
+ /*FALLTHROUGH*/
+ case 7:
+ break;
+ }
+ return hval;
+}
+
+const struct cp_trait *
+cp_trait_lookup::find (const char *str, size_t len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 45,
+ MIN_WORD_LENGTH = 7,
+ MAX_WORD_LENGTH = 37,
+ MIN_HASH_VALUE = 7,
+ MAX_HASH_VALUE = 85
+ };
+
+ static const struct cp_trait wordlist[] =
+ {
+#line 73 "../../gcc/cp/cp-trait.gperf"
+ {"__bases", CPTK_BASES, 1, true},
+#line 56 "../../gcc/cp/cp-trait.gperf"
+ {"__is_pod", CPTK_IS_POD, 1, false},
+#line 48 "../../gcc/cp/cp-trait.gperf"
+ {"__is_enum", CPTK_IS_ENUM, 1, false},
+#line 64 "../../gcc/cp/cp-trait.gperf"
+ {"__is_union", CPTK_IS_UNION, 1, false},
+#line 44 "../../gcc/cp/cp-trait.gperf"
+ {"__is_class", CPTK_IS_CLASS, 1, false},
+#line 60 "../../gcc/cp/cp-trait.gperf"
+ {"__is_trivial", CPTK_IS_TRIVIAL, 1, false},
+#line 41 "../../gcc/cp/cp-trait.gperf"
+ {"__is_aggregate", CPTK_IS_AGGREGATE, 1, false},
+#line 72 "../../gcc/cp/cp-trait.gperf"
+ {"__is_deducible ", CPTK_IS_DEDUCIBLE, 2, false},
+#line 43 "../../gcc/cp/cp-trait.gperf"
+ {"__is_base_of", CPTK_IS_BASE_OF, 2, false},
+#line 40 "../../gcc/cp/cp-trait.gperf"
+ {"__is_abstract", CPTK_IS_ABSTRACT, 1, false},
+#line 58 "../../gcc/cp/cp-trait.gperf"
+ {"__is_same", CPTK_IS_SAME, 2, false},
+#line 42 "../../gcc/cp/cp-trait.gperf"
+ {"__is_assignable", CPTK_IS_ASSIGNABLE, 2, false},
+#line 59 "../../gcc/cp/cp-trait.gperf"
+ {"__is_standard_layout", CPTK_IS_STD_LAYOUT, 1, false},
+#line 30 "../../gcc/cp/cp-trait.gperf"
+ {"__is_same_as", CPTK_IS_SAME, 2, false},
+#line 63 "../../gcc/cp/cp-trait.gperf"
+ {"__is_trivially_copyable", CPTK_IS_TRIVIALLY_COPYABLE, 1, false},
+#line 39 "../../gcc/cp/cp-trait.gperf"
+ {"__has_virtual_destructor", CPTK_HAS_VIRTUAL_DESTRUCTOR, 1, false},
+#line 61 "../../gcc/cp/cp-trait.gperf"
+ {"__is_trivially_assignable", CPTK_IS_TRIVIALLY_ASSIGNABLE, 2, false},
+#line 57 "../../gcc/cp/cp-trait.gperf"
+ {"__is_polymorphic", CPTK_IS_POLYMORPHIC, 1, false},
+#line 71 "../../gcc/cp/cp-trait.gperf"
+ {"__underlying_type", CPTK_UNDERLYING_TYPE, 1, true},
+#line 62 "../../gcc/cp/cp-trait.gperf"
+ {"__is_trivially_constructible", CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, -1, false},
+#line 74 "../../gcc/cp/cp-trait.gperf"
+ {"__direct_bases", CPTK_DIRECT_BASES, 1, true},
+#line 51 "../../gcc/cp/cp-trait.gperf"
+ {"__is_literal_type", CPTK_IS_LITERAL_TYPE, 1, false},
+#line 33 "../../gcc/cp/cp-trait.gperf"
+ {"__has_nothrow_copy", CPTK_HAS_NOTHROW_COPY, 1, false},
+#line 31 "../../gcc/cp/cp-trait.gperf"
+ {"__has_nothrow_assign", CPTK_HAS_NOTHROW_ASSIGN, 1, false},
+#line 55 "../../gcc/cp/cp-trait.gperf"
+ {"__is_pointer_interconvertible_base_of", CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, 2, false},
+#line 52 "../../gcc/cp/cp-trait.gperf"
+ {"__is_nothrow_assignable", CPTK_IS_NOTHROW_ASSIGNABLE, 2, false},
+#line 54 "../../gcc/cp/cp-trait.gperf"
+ {"__is_nothrow_convertible", CPTK_IS_NOTHROW_CONVERTIBLE, 2, false},
+#line 32 "../../gcc/cp/cp-trait.gperf"
+ {"__has_nothrow_constructor", CPTK_HAS_NOTHROW_CONSTRUCTOR, 1, false},
+#line 53 "../../gcc/cp/cp-trait.gperf"
+ {"__is_nothrow_constructible", CPTK_IS_NOTHROW_CONSTRUCTIBLE, -1, false},
+#line 50 "../../gcc/cp/cp-trait.gperf"
+ {"__is_layout_compatible", CPTK_IS_LAYOUT_COMPATIBLE, 2, false},
+#line 67 "../../gcc/cp/cp-trait.gperf"
+ {"__remove_cv", CPTK_REMOVE_CV, 1, true},
+#line 36 "../../gcc/cp/cp-trait.gperf"
+ {"__has_trivial_copy", CPTK_HAS_TRIVIAL_COPY, 1, false},
+#line 68 "../../gcc/cp/cp-trait.gperf"
+ {"__remove_cvref", CPTK_REMOVE_CVREF, 1, true},
+#line 34 "../../gcc/cp/cp-trait.gperf"
+ {"__has_trivial_assign", CPTK_HAS_TRIVIAL_ASSIGN, 1, false},
+#line 69 "../../gcc/cp/cp-trait.gperf"
+ {"__remove_reference", CPTK_REMOVE_REFERENCE, 1, true},
+#line 37 "../../gcc/cp/cp-trait.gperf"
+ {"__has_trivial_destructor", CPTK_HAS_TRIVIAL_DESTRUCTOR, 1, false},
+#line 35 "../../gcc/cp/cp-trait.gperf"
+ {"__has_trivial_constructor", CPTK_HAS_TRIVIAL_CONSTRUCTOR, 1, false},
+#line 49 "../../gcc/cp/cp-trait.gperf"
+ {"__is_final", CPTK_IS_FINAL, 1, false},
+#line 47 "../../gcc/cp/cp-trait.gperf"
+ {"__is_empty", CPTK_IS_EMPTY, 1, false},
+#line 46 "../../gcc/cp/cp-trait.gperf"
+ {"__is_convertible", CPTK_IS_CONVERTIBLE, 2, false},
+#line 45 "../../gcc/cp/cp-trait.gperf"
+ {"__is_constructible", CPTK_IS_CONSTRUCTIBLE, -1, false},
+#line 66 "../../gcc/cp/cp-trait.gperf"
+ {"__reference_converts_from_temporary", CPTK_REF_CONVERTS_FROM_TEMPORARY, 2, false},
+#line 65 "../../gcc/cp/cp-trait.gperf"
+ {"__reference_constructs_from_temporary", CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, 2, false},
+#line 70 "../../gcc/cp/cp-trait.gperf"
+ {"__type_pack_element", CPTK_TYPE_PACK_ELEMENT, -1, true},
+#line 38 "../../gcc/cp/cp-trait.gperf"
+ {"__has_unique_object_representations", CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, 1, false}
+ };
+
+ static const signed char lookup[] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, -1,
+ 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, -1, -1, 21, 22, -1, 23, -1, 24, 25, 26, 27, 28,
+ 29, -1, -1, -1, 30, -1, 31, 32, 33, -1, -1, 34, 35, 36,
+ -1, -1, -1, -1, 37, -1, -1, -1, -1, 38, 39, -1, 40, -1,
+ 41, -1, 42, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 44
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ int index = lookup[key];
+
+ if (index >= 0)
+ {
+ const char *s = wordlist[index].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[index];
+ }
+ }
+ }
+ return 0;
+}
@@ -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) \
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
static int interface_strcmp (const char *);
+static void init_cp_traits (void);
static void init_cp_pragma (void);
static tree parse_strconst_pragma (const char *, int);
@@ -283,6 +284,23 @@ init_reswords (void)
}
}
+/* Initialize the C++ traits. */
+static void
+init_cp_traits (void)
+{
+ tree id;
+
+#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
+ id = get_identifier (NAME); \
+ set_identifier_kind (id, cik_trait);
+#include "cp/cp-trait.def"
+#undef DEFTRAIT
+
+ /* An alias for __is_same. */
+ id = get_identifier ("__is_same_as");
+ set_identifier_kind (id, cik_trait);
+}
+
static void
init_cp_pragma (void)
{
@@ -324,6 +342,7 @@ cxx_init (void)
input_location = BUILTINS_LOCATION;
init_reswords ();
+ init_cp_traits ();
init_tree ();
init_cp_semantics ();
init_operators ();
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "contracts.h"
#include "bitmap.h"
#include "builtins.h"
+#include "cp-trait.h"
/* The lexer. */
@@ -246,6 +247,12 @@ static void cp_lexer_start_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
static void cp_lexer_stop_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
+static const cp_trait *cp_lexer_lookup_trait
+ (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_expr
+ (const cp_token *);
+static const cp_trait *cp_lexer_lookup_trait_type
+ (const cp_token *);
static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *);
@@ -1167,12 +1174,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
case RID_CONSTEVAL:
return true;
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
- case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
- return true;
-
default:
if (keyword >= RID_FIRST_INT_N
&& keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
@@ -1182,6 +1183,51 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
}
}
+/* Look ups the corresponding built-in trait if a given token is
+ a built-in trait. Otherwise, returns nullptr. */
+
+static const cp_trait *
+cp_lexer_lookup_trait (const cp_token *token)
+{
+ tree id = token->u.value;
+
+ if (token->type == CPP_NAME
+ && TREE_CODE (id) == IDENTIFIER_NODE
+ && IDENTIFIER_TRAIT_P (id))
+ {
+ const char *id_str = IDENTIFIER_POINTER (id);
+ const int id_len = IDENTIFIER_LENGTH (id);
+ return cp_trait_lookup::find (id_str, id_len);
+ }
+ return nullptr;
+}
+
+/* Similarly, but only if the token is an expression-yielding
+ built-in trait. */
+
+static const cp_trait *
+cp_lexer_lookup_trait_expr (const cp_token *token)
+{
+ const cp_trait *trait = cp_lexer_lookup_trait (token);
+ if (trait && !trait->type)
+ return trait;
+
+ return nullptr;
+}
+
+/* Similarly, but only if the token is a type-yielding
+ built-in trait. */
+
+static const cp_trait *
+cp_lexer_lookup_trait_type (const cp_token *token)
+{
+ const cp_trait *trait = cp_lexer_lookup_trait (token);
+ if (trait && trait->type)
+ return trait;
+
+ return nullptr;
+}
+
/* Return true if the next token is a keyword for a decl-specifier. */
static bool
@@ -1190,6 +1236,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
cp_token *token;
token = cp_lexer_peek_token (lexer);
+ if (cp_lexer_lookup_trait_type (token))
+ return true;
return cp_keyword_starts_decl_specifier_p (token->keyword);
}
@@ -2854,7 +2902,7 @@ static void cp_parser_late_parsing_default_args
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static cp_expr cp_parser_trait
- (cp_parser *, enum rid);
+ (cp_parser *, const cp_trait *);
static bool cp_parser_declares_only_class_p
(cp_parser *);
static void cp_parser_set_storage_class
@@ -6021,12 +6069,6 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_OFFSETOF:
return cp_parser_builtin_offsetof (parser);
-#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \
- case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_EXPR
- return cp_parser_trait (parser, token->keyword);
-
// C++ concepts
case RID_REQUIRES:
return cp_parser_requires_expression (parser);
@@ -6065,6 +6107,12 @@ cp_parser_primary_expression (cp_parser *parser,
`::' as the beginning of a qualified-id, or the "operator"
keyword. */
case CPP_NAME:
+ {
+ const cp_trait* trait = cp_lexer_lookup_trait_expr (token);
+ if (trait)
+ return cp_parser_trait (parser, trait);
+ }
+ /* FALLTHRU */
case CPP_SCOPE:
case CPP_TEMPLATE_ID:
case CPP_NESTED_NAME_SPECIFIER:
@@ -11033,28 +11081,11 @@ cp_parser_builtin_offsetof (cp_parser *parser)
/* Parse a builtin trait expression or type. */
static cp_expr
-cp_parser_trait (cp_parser* parser, enum rid keyword)
+cp_parser_trait (cp_parser* parser, const cp_trait* trait)
{
- cp_trait_kind kind;
tree type1, type2 = NULL_TREE;
- bool binary = false;
- bool variadic = false;
- bool type = false;
-
- switch (keyword)
- {
-#define DEFTRAIT(TCC, CODE, NAME, ARITY) \
- case RID_##CODE: \
- kind = CPTK_##CODE; \
- binary = (ARITY == 2); \
- variadic = (ARITY == -1); \
- type = (TCC == tcc_type); \
- break;
-#include "cp-trait.def"
-#undef DEFTRAIT
- default:
- gcc_unreachable ();
- }
+ const bool binary = (trait->arity == 2);
+ const bool variadic = (trait->arity == -1);
/* Get location of initial token. */
location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -11063,12 +11094,12 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
cp_lexer_consume_token (parser->lexer);
matching_parens parens;
- if (kind == CPTK_TYPE_PACK_ELEMENT)
+ if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
cp_parser_require (parser, CPP_LESS, RT_LESS);
else
parens.require_open (parser);
- if (kind == CPTK_IS_DEDUCIBLE)
+ if (trait->kind == CPTK_IS_DEDUCIBLE)
{
const cp_token* token = cp_lexer_peek_token (parser->lexer);
type1 = cp_parser_id_expression (parser,
@@ -11079,7 +11110,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
/*optional_p=*/false);
type1 = cp_parser_lookup_name_simple (parser, type1, token->location);
}
- else if (kind == CPTK_TYPE_PACK_ELEMENT)
+ else if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
/* __type_pack_element takes an expression as its first argument and uses
template-id syntax instead of function call syntax (for consistency
with Clang). We special case these properties of __type_pack_element
@@ -11094,7 +11125,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
if (type1 == error_mark_node)
return error_mark_node;
- if (kind == CPTK_TYPE_PACK_ELEMENT)
+ if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
{
cp_parser_require (parser, CPP_COMMA, RT_COMMA);
tree trailing = cp_parser_enclosed_template_argument_list (parser);
@@ -11144,7 +11175,7 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
}
location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
- if (kind == CPTK_TYPE_PACK_ELEMENT)
+ if (trait->kind == CPTK_TYPE_PACK_ELEMENT)
/* cp_parser_enclosed_template_argument_list above already took care
of parsing the closing '>'. */;
else
@@ -11158,17 +11189,17 @@ cp_parser_trait (cp_parser* parser, enum rid keyword)
/* Complete the trait expression, which may mean either processing
the trait expr now or saving it for template instantiation. */
- switch (kind)
+ switch (trait->kind)
{
case CPTK_BASES:
return cp_expr (finish_bases (type1, false), trait_loc);
case CPTK_DIRECT_BASES:
return cp_expr (finish_bases (type1, true), trait_loc);
default:
- if (type)
- return finish_trait_type (kind, type1, type2, tf_warning_or_error);
+ if (trait->type)
+ return finish_trait_type (trait->kind, type1, type2, tf_warning_or_error);
else
- return finish_trait_expr (trait_loc, kind, type1, type2);
+ return finish_trait_expr (trait_loc, trait->kind, type1, type2);
}
}
@@ -20081,20 +20112,21 @@ cp_parser_simple_type_specifier (cp_parser* parser,
return type;
-#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
- case RID_##CODE:
-#include "cp-trait.def"
-#undef DEFTRAIT_TYPE
- type = cp_parser_trait (parser, token->keyword);
+ default:
+ break;
+ }
+
+ /* If token is a type-yielding built-in traits, parse it. */
+ const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+ if (trait)
+ {
+ type = cp_parser_trait (parser, trait);
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs, type,
token,
/*type_definition_p=*/false);
return type;
-
- default:
- break;
}
/* If token is an already-parsed decltype not followed by ::,