Message ID | 20220929150504.829703-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | [RFC] c++: streamline process for adding new builtin trait | expand |
On Thu, 29 Sep 2022, Patrick Palka wrote: > Adding a new builtin trait currently involves some boilerplate (as can > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > CPTK_ enumerators and adding them to various switch statements across > many files. The exact switch statements we need to change is determined > by whether the proposed trait yields a type or an expression. > > This RFC patch attempts to streamline this process via a centralized > cp-trait.def file for declaring the important parts about a builtin trait > (whether it yields a type or an expression, its code, its spelling and > its arity) and using this file to automate away the switch statement > addition boilerplate. It also converts 9 traits to use this approach > by way of example (we can convert all the traits once the design is > settled). > > After this change, the process of adding a new builtin trait is just > (modulo tests): declare it in cp-trait.def, define its behavior in > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > an expression-yielding trait (this last step is unfortunate but since > the switch has no default case, we'll at least get a diagnostic if we > forget to do it). Here's an example of adding e.g. __remove_const using this framework: gcc/cp/cp-trait.def | 1 + gcc/cp/semantics.cc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def index 817951f3e42..f6ad16e38cf 100644 --- a/gcc/cp/cp-trait.def +++ b/gcc/cp/cp-trait.def @@ -25,6 +25,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) +DEFTRAIT_TYPE (REMOVE_CONST, "__remove_const", 1) #ifdef DEFTRAIT_EXPR_DEFAULTED #undef DEFTRAIT_EXPR diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 66ee2186a84..eaf608085ae 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12250,6 +12250,9 @@ finish_trait_type (cp_trait_kind kind, tree type1, tree type2) if (TYPE_REF_P (type1)) type1 = TREE_TYPE (type1); return cv_unqualified (type1); + case CPTK_REMOVE_CONST: + return cp_build_qualified_type (type1, + cp_type_quals (type1) & ~TYPE_QUAL_CONST); default: gcc_unreachable (); } That's it! > > Does this look like a good approach? > > gcc/c-family/ChangeLog: > > * c-common.cc (c_common_reswords): Use cp/cp-trait.def > to handle C++ traits. > * c-common.h (enum rid): Likewise. > > gcc/cp/ChangeLog: > > * constraint.cc (diagnose_trait_expr): Likewise. > * cp-objcp-common.cc (names_builtin_p): Likewise. > * cp-tree.h (enum cp_trait_kind): Likewise. > * cxx-pretty-print (pp_cxx_trait): Likewise. > * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. > (cp_parser_primary_expression): Likewise. > (cp_parser_trait): Likewise. > (cp_parser_simple_type_specifier): Likewise. > * cp-trait.def: New file. > --- > gcc/c-family/c-common.cc | 13 +++----- > gcc/c-family/c-common.h | 8 ++--- > gcc/cp/constraint.cc | 7 ++-- > gcc/cp/cp-objcp-common.cc | 13 +++----- > gcc/cp/cp-trait.def | 37 +++++++++++++++++++++ > gcc/cp/cp-tree.h | 13 +++----- > gcc/cp/cxx-pretty-print.cc | 31 +++--------------- > gcc/cp/parser.cc | 67 ++++++++++++-------------------------- > 8 files changed, 82 insertions(+), 107 deletions(-) > create mode 100644 gcc/cp/cp-trait.def > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > index 6e0af863a49..1b2fd37c583 100644 > --- a/gcc/c-family/c-common.cc > +++ b/gcc/c-family/c-common.cc > @@ -537,19 +537,14 @@ const struct c_common_resword c_common_reswords[] = > { "volatile", RID_VOLATILE, 0 }, > { "wchar_t", RID_WCHAR, D_CXXONLY }, > { "while", RID_WHILE, 0 }, > - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, > - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, > - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, > - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, > { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, > D_CXXONLY }, > { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, > D_CXXONLY }, > - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, > - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, > - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + { NAME, RID_##CODE, D_CXXONLY }, > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > > /* C++ transactional memory. */ > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index d5c98d306ce..b306815c23b 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -182,12 +182,12 @@ enum rid > RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, > RID_IS_TRIVIALLY_COPYABLE, > RID_IS_UNION, RID_UNDERLYING_TYPE, > - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, > - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, > - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, > RID_REF_CONSTRUCTS_FROM_TEMPORARY, > RID_REF_CONVERTS_FROM_TEMPORARY, > - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, > +#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/constraint.cc b/gcc/cp/constraint.cc > index ca73aff3f38..9323bb091e1 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -3714,9 +3714,10 @@ diagnose_trait_expr (tree expr, tree args) > case CPTK_BASES: > case CPTK_DIRECT_BASES: > case CPTK_UNDERLYING_TYPE: > - case CPTK_REMOVE_CV: > - case CPTK_REMOVE_REFERENCE: > - case CPTK_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case CPTK_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > /* We shouldn't see these non-expression traits. */ > gcc_unreachable (); > /* We deliberately omit the default case so that when adding a new > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc > index 2d3f206b530..bc397a5447f 100644 > --- a/gcc/cp/cp-objcp-common.cc > +++ b/gcc/cp/cp-objcp-common.cc > @@ -458,18 +458,13 @@ names_builtin_p (const char *name) > case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > case RID_IS_TRIVIALLY_COPYABLE: > case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > case RID_UNDERLYING_TYPE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > case RID_REF_CONVERTS_FROM_TEMPORARY: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > return true; > default: > break; > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def > new file mode 100644 > index 00000000000..817951f3e42 > --- /dev/null > +++ b/gcc/cp/cp-trait.def > @@ -0,0 +1,37 @@ > +#ifdef DEFTRAIT > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_EXPR > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_TYPE > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) > +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) > +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) > +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) > +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) > +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) > + > +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) > +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) > + > +#ifdef DEFTRAIT_EXPR_DEFAULTED > +#undef DEFTRAIT_EXPR > +#undef DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifdef DEFTRAIT_TYPE_DEFAULTED > +#undef DEFTRAIT_TYPE > +#undef DEFTRAIT_TYPE_DEFAULTED > +#endif > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 3cbcdf726ca..8c5a85ab5fe 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -1405,17 +1405,12 @@ enum cp_trait_kind > CPTK_IS_TRIVIALLY_COPYABLE, > CPTK_IS_UNION, > CPTK_UNDERLYING_TYPE, > - CPTK_IS_ASSIGNABLE, > - CPTK_IS_CONSTRUCTIBLE, > - CPTK_IS_NOTHROW_ASSIGNABLE, > - CPTK_IS_NOTHROW_CONSTRUCTIBLE, > - CPTK_IS_CONVERTIBLE, > - CPTK_IS_NOTHROW_CONVERTIBLE, > CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, > CPTK_REF_CONVERTS_FROM_TEMPORARY, > - CPTK_REMOVE_CV, > - CPTK_REMOVE_REFERENCE, > - CPTK_REMOVE_CVREF, > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + CPTK_##CODE, > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > }; > > /* The types that we are processing. */ > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > index b91615439e4..a2ddbcb899a 100644 > --- a/gcc/cp/cxx-pretty-print.cc > +++ b/gcc/cp/cxx-pretty-print.cc > @@ -2701,24 +2701,6 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > case CPTK_IS_LITERAL_TYPE: > pp_cxx_ws_string (pp, "__is_literal_type"); > break; > - case CPTK_IS_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_assignable"); > - break; > - case CPTK_IS_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_constructible"); > - break; > - case CPTK_IS_NOTHROW_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); > - break; > - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); > - break; > - case CPTK_IS_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_convertible"); > - break; > - case CPTK_IS_NOTHROW_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); > - break; > case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: > pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); > break; > @@ -2728,15 +2710,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > case CPTK_UNDERLYING_TYPE: > pp_cxx_ws_string (pp, "__underlying_type"); > break; > - case CPTK_REMOVE_CV: > - pp_cxx_ws_string (pp, "__remove_cv"); > - break; > - case CPTK_REMOVE_REFERENCE: > - pp_cxx_ws_string (pp, "__remove_reference"); > - break; > - case CPTK_REMOVE_CVREF: > - pp_cxx_ws_string (pp, "__remove_cvref"); > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case CPTK_##CODE: \ > + pp_cxx_ws_string (pp, NAME); \ > break; > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > default: > gcc_unreachable (); > } > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index d592d783250..138892716b4 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -1147,9 +1147,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) > /* C++11 extensions. */ > case RID_DECLTYPE: > case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > case RID_CONSTEXPR: > /* C++20 extensions. */ > case RID_CONSTINIT: > @@ -5923,14 +5924,12 @@ cp_parser_primary_expression (cp_parser *parser, > case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > case RID_IS_TRIVIALLY_COPYABLE: > case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > case RID_REF_CONVERTS_FROM_TEMPORARY: > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_EXPR > return cp_parser_trait (parser, token->keyword); > > // C++ concepts > @@ -10998,30 +10997,6 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > case RID_DIRECT_BASES: > kind = CPTK_DIRECT_BASES; > break; > - case RID_IS_ASSIGNABLE: > - kind = CPTK_IS_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_CONSTRUCTIBLE: > - kind = CPTK_IS_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_NOTHROW_ASSIGNABLE: > - kind = CPTK_IS_NOTHROW_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_CONVERTIBLE: > - kind = CPTK_IS_CONVERTIBLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONVERTIBLE: > - kind = CPTK_IS_NOTHROW_CONVERTIBLE; > - binary = true; > - break; > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; > binary = true; > @@ -11030,18 +11005,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; > binary = true; > break; > - case RID_REMOVE_CV: > - kind = CPTK_REMOVE_CV; > - type = true; > - break; > - case RID_REMOVE_REFERENCE: > - kind = CPTK_REMOVE_REFERENCE; > - type = true; > - break; > - case RID_REMOVE_CVREF: > - kind = CPTK_REMOVE_CVREF; > - type = true; > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case RID_##CODE: \ > + type = (TCC == tcc_type); \ > + kind = CPTK_##CODE; \ > + binary = (ARITY == 2); \ > + variadic = (ARITY == -1); \ > break; > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > default: > gcc_unreachable (); > } > @@ -19882,9 +19854,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, > return type; > > case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > type = cp_parser_trait (parser, token->keyword); > if (decl_specs) > cp_parser_set_decl_spec_type (decl_specs, type, > -- > 2.38.0.rc2 > >
On Thu, Sep 29, 2022 at 11:05:04AM -0400, Patrick Palka via Gcc-patches wrote: > Adding a new builtin trait currently involves some boilerplate (as can > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > CPTK_ enumerators and adding them to various switch statements across > many files. The exact switch statements we need to change is determined > by whether the proposed trait yields a type or an expression. > > This RFC patch attempts to streamline this process via a centralized > cp-trait.def file for declaring the important parts about a builtin trait > (whether it yields a type or an expression, its code, its spelling and > its arity) and using this file to automate away the switch statement > addition boilerplate. It also converts 9 traits to use this approach > by way of example (we can convert all the traits once the design is > settled). > > After this change, the process of adding a new builtin trait is just > (modulo tests): declare it in cp-trait.def, define its behavior in > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > an expression-yielding trait (this last step is unfortunate but since > the switch has no default case, we'll at least get a diagnostic if we > forget to do it). > > Does this look like a good approach? I think it'd be fantastic to have this. It's been very easy to forget to update pp_cxx_trait, or names_builtin_p. cp-trait.def just needs to describe what the arguments mean. Marek
On Thu, 29 Sep 2022, Marek Polacek wrote: > On Thu, Sep 29, 2022 at 11:05:04AM -0400, Patrick Palka via Gcc-patches wrote: > > Adding a new builtin trait currently involves some boilerplate (as can > > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > > CPTK_ enumerators and adding them to various switch statements across > > many files. The exact switch statements we need to change is determined > > by whether the proposed trait yields a type or an expression. > > > > This RFC patch attempts to streamline this process via a centralized > > cp-trait.def file for declaring the important parts about a builtin trait > > (whether it yields a type or an expression, its code, its spelling and > > its arity) and using this file to automate away the switch statement > > addition boilerplate. It also converts 9 traits to use this approach > > by way of example (we can convert all the traits once the design is > > settled). > > > > After this change, the process of adding a new builtin trait is just > > (modulo tests): declare it in cp-trait.def, define its behavior in > > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > > an expression-yielding trait (this last step is unfortunate but since > > the switch has no default case, we'll at least get a diagnostic if we > > forget to do it). > > > > Does this look like a good approach? > > I think it'd be fantastic to have this. It's been very easy to forget > to update pp_cxx_trait, or names_builtin_p. cp-trait.def just needs to > describe what the arguments mean. Here's v2 which documents cp-trait.def and factors out its macro definitions into cp-trait-head.h and cp-trait-tail.h: -- >8 -- gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Use cp/cp-trait.def to handle C++ traits. * c-common.h (enum rid): Likewise. gcc/cp/ChangeLog: * constraint.cc (diagnose_trait_expr): Likewise. * cp-objcp-common.cc (names_builtin_p): Likewise. * cp-tree.h (enum cp_trait_kind): Likewise. * cxx-pretty-print (pp_cxx_trait): Likewise. * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. (cp_parser_primary_expression): Likewise. (cp_parser_trait): Likewise. (cp_parser_simple_type_specifier): Likewise. * cp-trait-head.h: New file. * cp-trait-tail.h: New file. * cp-trait.def: New file. --- gcc/c-family/c-common.cc | 13 +++----- gcc/c-family/c-common.h | 8 ++--- gcc/cp/constraint.cc | 7 ++-- gcc/cp/cp-objcp-common.cc | 13 +++----- gcc/cp/cp-trait-head.h | 48 +++++++++++++++++++++++++++ gcc/cp/cp-trait-tail.h | 30 +++++++++++++++++ gcc/cp/cp-trait.def | 45 +++++++++++++++++++++++++ gcc/cp/cp-tree.h | 13 +++----- gcc/cp/cxx-pretty-print.cc | 31 +++--------------- gcc/cp/parser.cc | 67 ++++++++++++-------------------------- 10 files changed, 168 insertions(+), 107 deletions(-) create mode 100644 gcc/cp/cp-trait-head.h create mode 100644 gcc/cp/cp-trait-tail.h create mode 100644 gcc/cp/cp-trait.def diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 6e0af863a49..1b2fd37c583 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -537,19 +537,14 @@ const struct c_common_resword c_common_reswords[] = { "volatile", RID_VOLATILE, 0 }, { "wchar_t", RID_WCHAR, D_CXXONLY }, { "while", RID_WHILE, 0 }, - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, D_CXXONLY }, { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, D_CXXONLY }, - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + { NAME, RID_##CODE, D_CXXONLY }, +#include "cp/cp-trait.def" +#undef DEFTRAIT /* C++ transactional memory. */ { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5c98d306ce..b306815c23b 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -182,12 +182,12 @@ enum rid RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, RID_IS_TRIVIALLY_COPYABLE, RID_IS_UNION, RID_UNDERLYING_TYPE, - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, RID_REF_CONSTRUCTS_FROM_TEMPORARY, RID_REF_CONVERTS_FROM_TEMPORARY, - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, +#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/constraint.cc b/gcc/cp/constraint.cc index ca73aff3f38..9323bb091e1 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3714,9 +3714,10 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_BASES: case CPTK_DIRECT_BASES: case CPTK_UNDERLYING_TYPE: - case CPTK_REMOVE_CV: - case CPTK_REMOVE_REFERENCE: - case CPTK_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case CPTK_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE /* We shouldn't see these non-expression traits. */ gcc_unreachable (); /* We deliberately omit the default case so that when adding a new diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 2d3f206b530..bc397a5447f 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -458,18 +458,13 @@ names_builtin_p (const char *name) case RID_IS_TRIVIALLY_CONSTRUCTIBLE: case RID_IS_TRIVIALLY_COPYABLE: case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: case RID_UNDERLYING_TYPE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: case RID_REF_CONSTRUCTS_FROM_TEMPORARY: case RID_REF_CONVERTS_FROM_TEMPORARY: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT return true; default: break; diff --git a/gcc/cp/cp-trait-head.h b/gcc/cp/cp-trait-head.h new file mode 100644 index 00000000000..5cec25af041 --- /dev/null +++ b/gcc/cp/cp-trait-head.h @@ -0,0 +1,48 @@ +/* Convenience macro definitions for programmatically tabulating over traits + defined in cp-trait.def. Used only by cp-trait.def. + + Copyright The GNU Toolchain Authors. + + 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/>. */ + +/* Define DEFTRAIT(TCC, CODE, NAME, ARITY) and include cp-trait.def to + tabulate over all traits defined in cp-trait.def. The first argument + will be tcc_expression for expression-yielding traits and tcc_type for + type-yielding traits. */ + +#ifdef DEFTRAIT +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#define DEFTRAIT_TYPE_DEFAULTED +#endif + +/* Define DEFTRAIT_EXPR(CODE, NAME, ARITY) and include cp-trait.def to + tabulate over all expression-yielding traits. */ + +#ifndef DEFTRAIT_EXPR +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#endif + +/* Define DEFTRAIT_TYPE(CODE, NAME, ARITY) and include cp-trait.def to + tabulate over all type-yielding traits. */ + +#ifndef DEFTRAIT_TYPE +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) +#define DEFTRAIT_TYPE_DEFAULTED +#endif diff --git a/gcc/cp/cp-trait-tail.h b/gcc/cp/cp-trait-tail.h new file mode 100644 index 00000000000..cc8425119b2 --- /dev/null +++ b/gcc/cp/cp-trait-tail.h @@ -0,0 +1,30 @@ +/* Undefines the macros that may have been implicitly defined in + cp-trait-head.h. Used only by cp-trait.def. + + Copyright The GNU Toolchain Authors. + + 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/>. */ + +#ifdef DEFTRAIT_EXPR_DEFAULTED +#undef DEFTRAIT_EXPR +#undef DEFTRAIT_EXPR_DEFAULTED +#endif + +#ifdef DEFTRAIT_TYPE_DEFAULTED +#undef DEFTRAIT_TYPE +#undef DEFTRAIT_TYPE_DEFAULTED +#endif diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def new file mode 100644 index 00000000000..61a0bbfdfa5 --- /dev/null +++ b/gcc/cp/cp-trait.def @@ -0,0 +1,45 @@ +/* This file contains the definitions for C++-specific builtin traits. + + Copyright The GNU Toolchain Authors. + + 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/>. */ + +#include "cp-trait-head.h" + +/* Add a DEFTRAIT_EXPR (CODE, NAME, N) line to this file to define an + expression-yielding builtin trait with internal code name CODE, spelled + as NAME and takes exactly N type arguments (where N is either 1, 2, or + the special value -1 which denotes that it takes at least one argument). + Such traits are represented as TRAIT_EXPR tree whose TRAIT_EXPR_KIND is + CPTK_NAME. */ + +/* Add a DEFTRAIT_TYPE (CODE, NAME, N) line to this file to define a + type-yielding trait in the same manner as described above. Such traits + are represented as a TRAIT_TYPE tree whose TRAIT_TYPE_KIND is CPTK_NAME. */ + +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) + +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) + +#include "cp-trait-tail.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3cbcdf726ca..8c5a85ab5fe 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1405,17 +1405,12 @@ enum cp_trait_kind CPTK_IS_TRIVIALLY_COPYABLE, CPTK_IS_UNION, CPTK_UNDERLYING_TYPE, - CPTK_IS_ASSIGNABLE, - CPTK_IS_CONSTRUCTIBLE, - CPTK_IS_NOTHROW_ASSIGNABLE, - CPTK_IS_NOTHROW_CONSTRUCTIBLE, - CPTK_IS_CONVERTIBLE, - CPTK_IS_NOTHROW_CONVERTIBLE, CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, CPTK_REF_CONVERTS_FROM_TEMPORARY, - CPTK_REMOVE_CV, - CPTK_REMOVE_REFERENCE, - CPTK_REMOVE_CVREF, +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + CPTK_##CODE, +#include "cp/cp-trait.def" +#undef DEFTRAIT }; /* The types that we are processing. */ diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index b91615439e4..a2ddbcb899a 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -2701,24 +2701,6 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) case CPTK_IS_LITERAL_TYPE: pp_cxx_ws_string (pp, "__is_literal_type"); break; - case CPTK_IS_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_assignable"); - break; - case CPTK_IS_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_constructible"); - break; - case CPTK_IS_NOTHROW_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); - break; - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); - break; - case CPTK_IS_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_convertible"); - break; - case CPTK_IS_NOTHROW_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); - break; case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); break; @@ -2728,15 +2710,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) case CPTK_UNDERLYING_TYPE: pp_cxx_ws_string (pp, "__underlying_type"); break; - case CPTK_REMOVE_CV: - pp_cxx_ws_string (pp, "__remove_cv"); - break; - case CPTK_REMOVE_REFERENCE: - pp_cxx_ws_string (pp, "__remove_reference"); - break; - case CPTK_REMOVE_CVREF: - pp_cxx_ws_string (pp, "__remove_cvref"); +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case CPTK_##CODE: \ + pp_cxx_ws_string (pp, NAME); \ break; +#include "cp/cp-trait.def" +#undef DEFTRAIT default: gcc_unreachable (); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d592d783250..138892716b4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1147,9 +1147,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) /* C++11 extensions. */ case RID_DECLTYPE: case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE case RID_CONSTEXPR: /* C++20 extensions. */ case RID_CONSTINIT: @@ -5923,14 +5924,12 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_TRIVIALLY_CONSTRUCTIBLE: case RID_IS_TRIVIALLY_COPYABLE: case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: case RID_REF_CONSTRUCTS_FROM_TEMPORARY: case RID_REF_CONVERTS_FROM_TEMPORARY: +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_EXPR return cp_parser_trait (parser, token->keyword); // C++ concepts @@ -10998,30 +10997,6 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) case RID_DIRECT_BASES: kind = CPTK_DIRECT_BASES; break; - case RID_IS_ASSIGNABLE: - kind = CPTK_IS_ASSIGNABLE; - binary = true; - break; - case RID_IS_CONSTRUCTIBLE: - kind = CPTK_IS_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_NOTHROW_ASSIGNABLE: - kind = CPTK_IS_NOTHROW_ASSIGNABLE; - binary = true; - break; - case RID_IS_NOTHROW_CONSTRUCTIBLE: - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_CONVERTIBLE: - kind = CPTK_IS_CONVERTIBLE; - binary = true; - break; - case RID_IS_NOTHROW_CONVERTIBLE: - kind = CPTK_IS_NOTHROW_CONVERTIBLE; - binary = true; - break; case RID_REF_CONSTRUCTS_FROM_TEMPORARY: kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; binary = true; @@ -11030,18 +11005,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; binary = true; break; - case RID_REMOVE_CV: - kind = CPTK_REMOVE_CV; - type = true; - break; - case RID_REMOVE_REFERENCE: - kind = CPTK_REMOVE_REFERENCE; - type = true; - break; - case RID_REMOVE_CVREF: - kind = CPTK_REMOVE_CVREF; - type = true; +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case RID_##CODE: \ + type = (TCC == tcc_type); \ + kind = CPTK_##CODE; \ + binary = (ARITY == 2); \ + variadic = (ARITY == -1); \ break; +#include "cp/cp-trait.def" +#undef DEFTRAIT default: gcc_unreachable (); } @@ -19882,9 +19854,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, return type; case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE type = cp_parser_trait (parser, token->keyword); if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type,
On 9/29/22 11:05, Patrick Palka wrote: > Adding a new builtin trait currently involves some boilerplate (as can > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > CPTK_ enumerators and adding them to various switch statements across > many files. The exact switch statements we need to change is determined > by whether the proposed trait yields a type or an expression. > > This RFC patch attempts to streamline this process via a centralized > cp-trait.def file for declaring the important parts about a builtin trait > (whether it yields a type or an expression, its code, its spelling and > its arity) and using this file to automate away the switch statement > addition boilerplate. It also converts 9 traits to use this approach > by way of example (we can convert all the traits once the design is > settled). > > After this change, the process of adding a new builtin trait is just > (modulo tests): declare it in cp-trait.def, define its behavior in > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > an expression-yielding trait (this last step is unfortunate but since > the switch has no default case, we'll at least get a diagnostic if we > forget to do it). > > Does this look like a good approach? OK. > gcc/c-family/ChangeLog: > > * c-common.cc (c_common_reswords): Use cp/cp-trait.def > to handle C++ traits. > * c-common.h (enum rid): Likewise. > > gcc/cp/ChangeLog: > > * constraint.cc (diagnose_trait_expr): Likewise. > * cp-objcp-common.cc (names_builtin_p): Likewise. > * cp-tree.h (enum cp_trait_kind): Likewise. > * cxx-pretty-print (pp_cxx_trait): Likewise. > * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. > (cp_parser_primary_expression): Likewise. > (cp_parser_trait): Likewise. > (cp_parser_simple_type_specifier): Likewise. > * cp-trait.def: New file. > --- > gcc/c-family/c-common.cc | 13 +++----- > gcc/c-family/c-common.h | 8 ++--- > gcc/cp/constraint.cc | 7 ++-- > gcc/cp/cp-objcp-common.cc | 13 +++----- > gcc/cp/cp-trait.def | 37 +++++++++++++++++++++ > gcc/cp/cp-tree.h | 13 +++----- > gcc/cp/cxx-pretty-print.cc | 31 +++--------------- > gcc/cp/parser.cc | 67 ++++++++++++-------------------------- > 8 files changed, 82 insertions(+), 107 deletions(-) > create mode 100644 gcc/cp/cp-trait.def > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > index 6e0af863a49..1b2fd37c583 100644 > --- a/gcc/c-family/c-common.cc > +++ b/gcc/c-family/c-common.cc > @@ -537,19 +537,14 @@ const struct c_common_resword c_common_reswords[] = > { "volatile", RID_VOLATILE, 0 }, > { "wchar_t", RID_WCHAR, D_CXXONLY }, > { "while", RID_WHILE, 0 }, > - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, > - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, > - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, > - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, > { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, > D_CXXONLY }, > { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, > D_CXXONLY }, > - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, > - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, > - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + { NAME, RID_##CODE, D_CXXONLY }, > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > > /* C++ transactional memory. */ > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index d5c98d306ce..b306815c23b 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -182,12 +182,12 @@ enum rid > RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, > RID_IS_TRIVIALLY_COPYABLE, > RID_IS_UNION, RID_UNDERLYING_TYPE, > - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, > - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, > - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, > RID_REF_CONSTRUCTS_FROM_TEMPORARY, > RID_REF_CONVERTS_FROM_TEMPORARY, > - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, > +#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/constraint.cc b/gcc/cp/constraint.cc > index ca73aff3f38..9323bb091e1 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -3714,9 +3714,10 @@ diagnose_trait_expr (tree expr, tree args) > case CPTK_BASES: > case CPTK_DIRECT_BASES: > case CPTK_UNDERLYING_TYPE: > - case CPTK_REMOVE_CV: > - case CPTK_REMOVE_REFERENCE: > - case CPTK_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case CPTK_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > /* We shouldn't see these non-expression traits. */ > gcc_unreachable (); > /* We deliberately omit the default case so that when adding a new > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc > index 2d3f206b530..bc397a5447f 100644 > --- a/gcc/cp/cp-objcp-common.cc > +++ b/gcc/cp/cp-objcp-common.cc > @@ -458,18 +458,13 @@ names_builtin_p (const char *name) > case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > case RID_IS_TRIVIALLY_COPYABLE: > case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > case RID_UNDERLYING_TYPE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > case RID_REF_CONVERTS_FROM_TEMPORARY: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > return true; > default: > break; > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def > new file mode 100644 > index 00000000000..817951f3e42 > --- /dev/null > +++ b/gcc/cp/cp-trait.def > @@ -0,0 +1,37 @@ > +#ifdef DEFTRAIT > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_EXPR > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_TYPE > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) > +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) > +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) > +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) > +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) > +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) > + > +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) > +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) > + > +#ifdef DEFTRAIT_EXPR_DEFAULTED > +#undef DEFTRAIT_EXPR > +#undef DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifdef DEFTRAIT_TYPE_DEFAULTED > +#undef DEFTRAIT_TYPE > +#undef DEFTRAIT_TYPE_DEFAULTED > +#endif > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index 3cbcdf726ca..8c5a85ab5fe 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -1405,17 +1405,12 @@ enum cp_trait_kind > CPTK_IS_TRIVIALLY_COPYABLE, > CPTK_IS_UNION, > CPTK_UNDERLYING_TYPE, > - CPTK_IS_ASSIGNABLE, > - CPTK_IS_CONSTRUCTIBLE, > - CPTK_IS_NOTHROW_ASSIGNABLE, > - CPTK_IS_NOTHROW_CONSTRUCTIBLE, > - CPTK_IS_CONVERTIBLE, > - CPTK_IS_NOTHROW_CONVERTIBLE, > CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, > CPTK_REF_CONVERTS_FROM_TEMPORARY, > - CPTK_REMOVE_CV, > - CPTK_REMOVE_REFERENCE, > - CPTK_REMOVE_CVREF, > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + CPTK_##CODE, > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > }; > > /* The types that we are processing. */ > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > index b91615439e4..a2ddbcb899a 100644 > --- a/gcc/cp/cxx-pretty-print.cc > +++ b/gcc/cp/cxx-pretty-print.cc > @@ -2701,24 +2701,6 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > case CPTK_IS_LITERAL_TYPE: > pp_cxx_ws_string (pp, "__is_literal_type"); > break; > - case CPTK_IS_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_assignable"); > - break; > - case CPTK_IS_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_constructible"); > - break; > - case CPTK_IS_NOTHROW_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); > - break; > - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); > - break; > - case CPTK_IS_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_convertible"); > - break; > - case CPTK_IS_NOTHROW_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); > - break; > case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: > pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); > break; > @@ -2728,15 +2710,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > case CPTK_UNDERLYING_TYPE: > pp_cxx_ws_string (pp, "__underlying_type"); > break; > - case CPTK_REMOVE_CV: > - pp_cxx_ws_string (pp, "__remove_cv"); > - break; > - case CPTK_REMOVE_REFERENCE: > - pp_cxx_ws_string (pp, "__remove_reference"); > - break; > - case CPTK_REMOVE_CVREF: > - pp_cxx_ws_string (pp, "__remove_cvref"); > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case CPTK_##CODE: \ > + pp_cxx_ws_string (pp, NAME); \ > break; > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > default: > gcc_unreachable (); > } > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index d592d783250..138892716b4 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -1147,9 +1147,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) > /* C++11 extensions. */ > case RID_DECLTYPE: > case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > case RID_CONSTEXPR: > /* C++20 extensions. */ > case RID_CONSTINIT: > @@ -5923,14 +5924,12 @@ cp_parser_primary_expression (cp_parser *parser, > case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > case RID_IS_TRIVIALLY_COPYABLE: > case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > case RID_REF_CONVERTS_FROM_TEMPORARY: > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_EXPR > return cp_parser_trait (parser, token->keyword); > > // C++ concepts > @@ -10998,30 +10997,6 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > case RID_DIRECT_BASES: > kind = CPTK_DIRECT_BASES; > break; > - case RID_IS_ASSIGNABLE: > - kind = CPTK_IS_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_CONSTRUCTIBLE: > - kind = CPTK_IS_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_NOTHROW_ASSIGNABLE: > - kind = CPTK_IS_NOTHROW_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_CONVERTIBLE: > - kind = CPTK_IS_CONVERTIBLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONVERTIBLE: > - kind = CPTK_IS_NOTHROW_CONVERTIBLE; > - binary = true; > - break; > case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; > binary = true; > @@ -11030,18 +11005,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; > binary = true; > break; > - case RID_REMOVE_CV: > - kind = CPTK_REMOVE_CV; > - type = true; > - break; > - case RID_REMOVE_REFERENCE: > - kind = CPTK_REMOVE_REFERENCE; > - type = true; > - break; > - case RID_REMOVE_CVREF: > - kind = CPTK_REMOVE_CVREF; > - type = true; > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case RID_##CODE: \ > + type = (TCC == tcc_type); \ > + kind = CPTK_##CODE; \ > + binary = (ARITY == 2); \ > + variadic = (ARITY == -1); \ > break; > +#include "cp/cp-trait.def" > +#undef DEFTRAIT > default: > gcc_unreachable (); > } > @@ -19882,9 +19854,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, > return type; > > case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp/cp-trait.def" > +#undef DEFTRAIT_TYPE > type = cp_parser_trait (parser, token->keyword); > if (decl_specs) > cp_parser_set_decl_spec_type (decl_specs, type,
On Thu, 29 Sep 2022, Jason Merrill wrote: > On 9/29/22 11:05, Patrick Palka wrote: > > Adding a new builtin trait currently involves some boilerplate (as can > > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > > CPTK_ enumerators and adding them to various switch statements across > > many files. The exact switch statements we need to change is determined > > by whether the proposed trait yields a type or an expression. > > > > This RFC patch attempts to streamline this process via a centralized > > cp-trait.def file for declaring the important parts about a builtin trait > > (whether it yields a type or an expression, its code, its spelling and > > its arity) and using this file to automate away the switch statement > > addition boilerplate. It also converts 9 traits to use this approach > > by way of example (we can convert all the traits once the design is > > settled). > > > > After this change, the process of adding a new builtin trait is just > > (modulo tests): declare it in cp-trait.def, define its behavior in > > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > > an expression-yielding trait (this last step is unfortunate but since > > the switch has no default case, we'll at least get a diagnostic if we > > forget to do it). > > > > Does this look like a good approach? > > OK. Thanks a lot, I committed the following (which migrates all the C++-specific traits to the new approach): -- >8 -- Subject: [PATCH] c++: streamline built-in trait addition process Adding a new built-in trait currently involves manual boilerplate consisting of defining an rid enumerator for the identifier as well as a corresponding cp_trait_kind enumerator and handling them in various switch statements, the exact set of which depends on whether the proposed trait yields (and thus is recognized as) a type or an expression. To streamline the process, this patch adds a central cp-trait.def file that tabulates the essential details about each built-in trait (whether it yields a type or an expression, its code, its spelling and its arity) and uses this file to automate away the manual boilerplate. It also migrates all the existing C++-specific built-in traits to use this approach. After this change, adding a new built-in trait just entails declaring it in cp-trait.def and defining its behavior in finish_trait_expr/type (and handling it in diagnose_trait_expr, if it's an expression-yielding trait). gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Use cp/cp-trait.def to handle C++ traits. * c-common.h (enum rid): Likewise. gcc/cp/ChangeLog: * constraint.cc (diagnose_trait_expr): Likewise. * cp-objcp-common.cc (names_builtin_p): Likewise. * cp-tree.h (enum cp_trait_kind): Likewise. * cxx-pretty-print.cc (pp_cxx_trait): Likewise. * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. (cp_parser_primary_expression): Likewise. (cp_parser_trait): Likewise. (cp_parser_simple_type_specifier): Likewise. * cp-trait.def: New file. --- gcc/c-family/c-common.cc | 54 ++------- gcc/c-family/c-common.h | 33 ++---- gcc/cp/constraint.cc | 12 +- gcc/cp/cp-objcp-common.cc | 44 +------- gcc/cp/cp-trait.def | 106 ++++++++++++++++++ gcc/cp/cp-tree.h | 46 +------- gcc/cp/cxx-pretty-print.cc | 126 +-------------------- gcc/cp/parser.cc | 217 ++++--------------------------------- 8 files changed, 161 insertions(+), 477 deletions(-) create mode 100644 gcc/cp/cp-trait.def diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 6e0af863a49..3c60a89bfe2 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -378,7 +378,6 @@ const struct c_common_resword c_common_reswords[] = { "__attribute", RID_ATTRIBUTE, 0 }, { "__attribute__", RID_ATTRIBUTE, 0 }, { "__auto_type", RID_AUTO_TYPE, D_CONLY }, - { "__bases", RID_BASES, D_CXXONLY }, { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY }, { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY }, { "__builtin_call_with_static_chain", @@ -401,44 +400,12 @@ const struct c_common_resword c_common_reswords[] = { "__const__", RID_CONST, 0 }, { "__constinit", RID_CONSTINIT, D_CXXONLY }, { "__decltype", RID_DECLTYPE, D_CXXONLY }, - { "__direct_bases", RID_DIRECT_BASES, D_CXXONLY }, { "__extension__", RID_EXTENSION, 0 }, { "__func__", RID_C99_FUNCTION_NAME, 0 }, - { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, - { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, - { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, - { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, - { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, - { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, - { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, - { "__has_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, - D_CXXONLY }, - { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, { "__imag", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 }, { "__inline", RID_INLINE, 0 }, { "__inline__", RID_INLINE, 0 }, - { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, - { "__is_aggregate", RID_IS_AGGREGATE, D_CXXONLY }, - { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, - { "__is_class", RID_IS_CLASS, D_CXXONLY }, - { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, - { "__is_enum", RID_IS_ENUM, D_CXXONLY }, - { "__is_final", RID_IS_FINAL, D_CXXONLY }, - { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, - { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, - { "__is_pointer_interconvertible_base_of", - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, - { "__is_pod", RID_IS_POD, D_CXXONLY }, - { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, - { "__is_same", RID_IS_SAME_AS, D_CXXONLY }, - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, - { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, - { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, - { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY }, - { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY }, - { "__is_union", RID_IS_UNION, D_CXXONLY }, { "__label__", RID_LABEL, 0 }, { "__null", RID_NULL, 0 }, { "__real", RID_REALPART, 0 }, @@ -453,7 +420,6 @@ const struct c_common_resword c_common_reswords[] = { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, - { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, { "__GIMPLE", RID_GIMPLE, D_CONLY }, @@ -537,19 +503,13 @@ const struct c_common_resword c_common_reswords[] = { "volatile", RID_VOLATILE, 0 }, { "wchar_t", RID_WCHAR, D_CXXONLY }, { "while", RID_WHILE, 0 }, - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, - { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, - D_CXXONLY }, - { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, - D_CXXONLY }, - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, + +#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_AS, D_CXXONLY }, /* C++ transactional memory. */ { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5c98d306ce..5f470d94f4a 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -163,31 +163,14 @@ enum rid RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, /* C++ extensions */ - RID_ADDRESSOF, RID_BASES, - RID_BUILTIN_LAUNDER, RID_DIRECT_BASES, - RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, - RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, - RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, - RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, - RID_HAS_VIRTUAL_DESTRUCTOR, RID_BUILTIN_BIT_CAST, - RID_IS_ABSTRACT, RID_IS_AGGREGATE, - RID_IS_BASE_OF, RID_IS_CLASS, - RID_IS_EMPTY, RID_IS_ENUM, - RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, - RID_IS_LITERAL_TYPE, - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, - RID_IS_POD, RID_IS_POLYMORPHIC, - RID_IS_SAME_AS, - RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, - RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, - RID_IS_TRIVIALLY_COPYABLE, - RID_IS_UNION, RID_UNDERLYING_TYPE, - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, - RID_REF_CONSTRUCTS_FROM_TEMPORARY, - RID_REF_CONVERTS_FROM_TEMPORARY, - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, + RID_ADDRESSOF, + 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/constraint.cc b/gcc/cp/constraint.cc index ca73aff3f38..f4145571d92 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3711,13 +3711,11 @@ diagnose_trait_expr (tree expr, tree args) inform (loc, " %qT is not a reference that binds to a temporary " "object of type %qT (copy-initialization)", t1, t2); break; - case CPTK_BASES: - case CPTK_DIRECT_BASES: - case CPTK_UNDERLYING_TYPE: - case CPTK_REMOVE_CV: - case CPTK_REMOVE_REFERENCE: - case CPTK_REMOVE_CVREF: - /* We shouldn't see these non-expression traits. */ +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case CPTK_##CODE: +#include "cp-trait.def" +#undef DEFTRAIT_TYPE + /* Type-yielding traits aren't expressions. */ gcc_unreachable (); /* We deliberately omit the default case so that when adding a new trait we'll get reminded (by way of a warning) to handle it here. */ diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 2d3f206b530..e4df30d9720 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -430,46 +430,10 @@ names_builtin_p (const char *name) case RID_BUILTIN_ASSOC_BARRIER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: - case RID_HAS_NOTHROW_ASSIGN: - case RID_HAS_NOTHROW_CONSTRUCTOR: - case RID_HAS_NOTHROW_COPY: - case RID_HAS_TRIVIAL_ASSIGN: - case RID_HAS_TRIVIAL_CONSTRUCTOR: - case RID_HAS_TRIVIAL_COPY: - case RID_HAS_TRIVIAL_DESTRUCTOR: - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: - case RID_HAS_VIRTUAL_DESTRUCTOR: - case RID_IS_ABSTRACT: - case RID_IS_AGGREGATE: - case RID_IS_BASE_OF: - case RID_IS_CLASS: - case RID_IS_EMPTY: - case RID_IS_ENUM: - case RID_IS_FINAL: - case RID_IS_LAYOUT_COMPATIBLE: - case RID_IS_LITERAL_TYPE: - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: - case RID_IS_POD: - case RID_IS_POLYMORPHIC: - case RID_IS_SAME_AS: - case RID_IS_STD_LAYOUT: - case RID_IS_TRIVIAL: - case RID_IS_TRIVIALLY_ASSIGNABLE: - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: - case RID_IS_TRIVIALLY_COPYABLE: - case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: - case RID_UNDERLYING_TYPE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: - case RID_REF_CONVERTS_FROM_TEMPORARY: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#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.def b/gcc/cp/cp-trait.def new file mode 100644 index 00000000000..922348a1659 --- /dev/null +++ b/gcc/cp/cp-trait.def @@ -0,0 +1,106 @@ +/* This file contains the definitions for C++-specific built-in traits. + + Copyright The GNU Toolchain Authors. + + 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/>. */ + +/* Add a DEFTRAIT_EXPR (CODE, NAME, N) line to this file to define an + expression-yielding built-in trait that has internal code name CODE, is + spelled as NAME and takes N type arguments (where N is either 1, 2, or + the special value -1 which denotes that it takes at least one argument). + Such traits are represented as TRAIT_EXPR tree whose TRAIT_EXPR_KIND is + CPTK_CODE. Define the behavior of the trait in finish_trait_expr. */ + +/* Add a DEFTRAIT_TYPE (CODE, NAME, N) line to this file to define a + type-yielding built-in trait as described above. Such traits are + generally represented as a TRAIT_TYPE tree whose TRAIT_TYPE_KIND is + CPTK_CODE (exceptions are BASES and DIRECT_BASES below). Define the + behavior of the trait in finish_trait_type. */ + +#ifdef DEFTRAIT +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#define DEFTRAIT_TYPE_DEFAULTED +#endif + +#ifndef DEFTRAIT_EXPR +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#endif + +#ifndef DEFTRAIT_TYPE +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) +#define DEFTRAIT_TYPE_DEFAULTED +#endif + +DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1) +DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1) +DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1) +DEFTRAIT_EXPR (HAS_TRIVIAL_ASSIGN, "__has_trivial_assign", 1) +DEFTRAIT_EXPR (HAS_TRIVIAL_CONSTRUCTOR, "__has_trivial_constructor", 1) +DEFTRAIT_EXPR (HAS_TRIVIAL_COPY, "__has_trivial_copy", 1) +DEFTRAIT_EXPR (HAS_TRIVIAL_DESTRUCTOR, "__has_trivial_destructor", 1) +DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representations", 1) +DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1) +DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1) +DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1) +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) +DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2) +DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) +DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1) +DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1) +DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1) +DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2) +DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1) +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) +DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) +DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) +DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) +DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) +DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1) +DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1) +DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2) +DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1) +DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1) +DEFTRAIT_EXPR (IS_UNION, "__is_union", 1) +DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2) +DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2) + +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1) + +/* These traits yield a type pack, not a type, and are represented by + cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree. */ +DEFTRAIT_TYPE (BASES, "__bases", 1) +DEFTRAIT_TYPE (DIRECT_BASES, "__direct_bases", 1) + +#ifdef DEFTRAIT_EXPR_DEFAULTED +#undef DEFTRAIT_EXPR +#undef DEFTRAIT_EXPR_DEFAULTED +#endif + +#ifdef DEFTRAIT_TYPE_DEFAULTED +#undef DEFTRAIT_TYPE +#undef DEFTRAIT_TYPE_DEFAULTED +#endif diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d696fd54a7a..67aea9653e3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1374,48 +1374,10 @@ struct GTY (()) tree_argument_pack_select { enum cp_trait_kind { - CPTK_BASES, - CPTK_DIRECT_BASES, - CPTK_HAS_NOTHROW_ASSIGN, - CPTK_HAS_NOTHROW_CONSTRUCTOR, - CPTK_HAS_NOTHROW_COPY, - CPTK_HAS_TRIVIAL_ASSIGN, - CPTK_HAS_TRIVIAL_CONSTRUCTOR, - CPTK_HAS_TRIVIAL_COPY, - CPTK_HAS_TRIVIAL_DESTRUCTOR, - CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, - CPTK_HAS_VIRTUAL_DESTRUCTOR, - CPTK_IS_ABSTRACT, - CPTK_IS_AGGREGATE, - CPTK_IS_BASE_OF, - CPTK_IS_CLASS, - CPTK_IS_EMPTY, - CPTK_IS_ENUM, - CPTK_IS_FINAL, - CPTK_IS_LAYOUT_COMPATIBLE, - CPTK_IS_LITERAL_TYPE, - CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, - CPTK_IS_POD, - CPTK_IS_POLYMORPHIC, - CPTK_IS_SAME_AS, - CPTK_IS_STD_LAYOUT, - CPTK_IS_TRIVIAL, - CPTK_IS_TRIVIALLY_ASSIGNABLE, - CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, - CPTK_IS_TRIVIALLY_COPYABLE, - CPTK_IS_UNION, - CPTK_UNDERLYING_TYPE, - CPTK_IS_ASSIGNABLE, - CPTK_IS_CONSTRUCTIBLE, - CPTK_IS_NOTHROW_ASSIGNABLE, - CPTK_IS_NOTHROW_CONSTRUCTIBLE, - CPTK_IS_CONVERTIBLE, - CPTK_IS_NOTHROW_CONVERTIBLE, - CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, - CPTK_REF_CONVERTS_FROM_TEMPORARY, - CPTK_REMOVE_CV, - CPTK_REMOVE_REFERENCE, - CPTK_REMOVE_CVREF, +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + CPTK_##CODE, +#include "cp-trait.def" +#undef DEFTRAIT }; /* The types that we are processing. */ diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index b91615439e4..8ca1b8f234a 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -2617,128 +2617,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) switch (kind) { - case CPTK_HAS_NOTHROW_ASSIGN: - pp_cxx_ws_string (pp, "__has_nothrow_assign"); +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case CPTK_##CODE: \ + pp_cxx_ws_string (pp, NAME); \ break; - case CPTK_HAS_TRIVIAL_ASSIGN: - pp_cxx_ws_string (pp, "__has_trivial_assign"); - break; - case CPTK_HAS_NOTHROW_CONSTRUCTOR: - pp_cxx_ws_string (pp, "__has_nothrow_constructor"); - break; - case CPTK_HAS_TRIVIAL_CONSTRUCTOR: - pp_cxx_ws_string (pp, "__has_trivial_constructor"); - break; - case CPTK_HAS_NOTHROW_COPY: - pp_cxx_ws_string (pp, "__has_nothrow_copy"); - break; - case CPTK_HAS_TRIVIAL_COPY: - pp_cxx_ws_string (pp, "__has_trivial_copy"); - break; - case CPTK_HAS_TRIVIAL_DESTRUCTOR: - pp_cxx_ws_string (pp, "__has_trivial_destructor"); - break; - case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: - pp_cxx_ws_string (pp, "__has_unique_object_representations"); - break; - case CPTK_HAS_VIRTUAL_DESTRUCTOR: - pp_cxx_ws_string (pp, "__has_virtual_destructor"); - break; - case CPTK_IS_ABSTRACT: - pp_cxx_ws_string (pp, "__is_abstract"); - break; - case CPTK_IS_AGGREGATE: - pp_cxx_ws_string (pp, "__is_aggregate"); - break; - case CPTK_IS_BASE_OF: - pp_cxx_ws_string (pp, "__is_base_of"); - break; - case CPTK_IS_CLASS: - pp_cxx_ws_string (pp, "__is_class"); - break; - case CPTK_IS_EMPTY: - pp_cxx_ws_string (pp, "__is_empty"); - break; - case CPTK_IS_ENUM: - pp_cxx_ws_string (pp, "__is_enum"); - break; - case CPTK_IS_FINAL: - pp_cxx_ws_string (pp, "__is_final"); - break; - case CPTK_IS_LAYOUT_COMPATIBLE: - pp_cxx_ws_string (pp, "__is_layout_compatible"); - break; - case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: - pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); - break; - case CPTK_IS_POD: - pp_cxx_ws_string (pp, "__is_pod"); - break; - case CPTK_IS_POLYMORPHIC: - pp_cxx_ws_string (pp, "__is_polymorphic"); - break; - case CPTK_IS_SAME_AS: - pp_cxx_ws_string (pp, "__is_same"); - break; - case CPTK_IS_STD_LAYOUT: - pp_cxx_ws_string (pp, "__is_std_layout"); - break; - case CPTK_IS_TRIVIAL: - pp_cxx_ws_string (pp, "__is_trivial"); - break; - case CPTK_IS_TRIVIALLY_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_trivially_assignable"); - break; - case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_trivially_constructible"); - break; - case CPTK_IS_TRIVIALLY_COPYABLE: - pp_cxx_ws_string (pp, "__is_trivially_copyable"); - break; - case CPTK_IS_UNION: - pp_cxx_ws_string (pp, "__is_union"); - break; - case CPTK_IS_LITERAL_TYPE: - pp_cxx_ws_string (pp, "__is_literal_type"); - break; - case CPTK_IS_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_assignable"); - break; - case CPTK_IS_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_constructible"); - break; - case CPTK_IS_NOTHROW_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); - break; - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); - break; - case CPTK_IS_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_convertible"); - break; - case CPTK_IS_NOTHROW_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); - break; - case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: - pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); - break; - case CPTK_REF_CONVERTS_FROM_TEMPORARY: - pp_cxx_ws_string (pp, "__reference_converts_from_temporary"); - break; - case CPTK_UNDERLYING_TYPE: - pp_cxx_ws_string (pp, "__underlying_type"); - break; - case CPTK_REMOVE_CV: - pp_cxx_ws_string (pp, "__remove_cv"); - break; - case CPTK_REMOVE_REFERENCE: - pp_cxx_ws_string (pp, "__remove_reference"); - break; - case CPTK_REMOVE_CVREF: - pp_cxx_ws_string (pp, "__remove_cvref"); - break; - default: - gcc_unreachable (); +#include "cp-trait.def" +#undef DEFTRAIT } pp_cxx_left_paren (pp); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d592d783250..8d0e0fa1b87 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1146,16 +1146,18 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) case RID_TYPEOF: /* C++11 extensions. */ case RID_DECLTYPE: - case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: case RID_CONSTEXPR: /* C++20 extensions. */ case RID_CONSTINIT: case RID_CONSTEVAL: return true; +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp-trait.def" +#undef DEFTRAIT_TYPE + return true; + default: if (keyword >= RID_FIRST_INT_N && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS @@ -5895,42 +5897,10 @@ cp_parser_primary_expression (cp_parser *parser, case RID_OFFSETOF: return cp_parser_builtin_offsetof (parser); - case RID_HAS_NOTHROW_ASSIGN: - case RID_HAS_NOTHROW_CONSTRUCTOR: - case RID_HAS_NOTHROW_COPY: - case RID_HAS_TRIVIAL_ASSIGN: - case RID_HAS_TRIVIAL_CONSTRUCTOR: - case RID_HAS_TRIVIAL_COPY: - case RID_HAS_TRIVIAL_DESTRUCTOR: - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: - case RID_HAS_VIRTUAL_DESTRUCTOR: - case RID_IS_ABSTRACT: - case RID_IS_AGGREGATE: - case RID_IS_BASE_OF: - case RID_IS_CLASS: - case RID_IS_EMPTY: - case RID_IS_ENUM: - case RID_IS_FINAL: - case RID_IS_LAYOUT_COMPATIBLE: - case RID_IS_LITERAL_TYPE: - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: - case RID_IS_POD: - case RID_IS_POLYMORPHIC: - case RID_IS_SAME_AS: - case RID_IS_STD_LAYOUT: - case RID_IS_TRIVIAL: - case RID_IS_TRIVIALLY_ASSIGNABLE: - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: - case RID_IS_TRIVIALLY_COPYABLE: - case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: - case RID_REF_CONVERTS_FROM_TEMPORARY: +#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 @@ -10898,150 +10868,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) switch (keyword) { - case RID_HAS_NOTHROW_ASSIGN: - kind = CPTK_HAS_NOTHROW_ASSIGN; - break; - case RID_HAS_NOTHROW_CONSTRUCTOR: - kind = CPTK_HAS_NOTHROW_CONSTRUCTOR; - break; - case RID_HAS_NOTHROW_COPY: - kind = CPTK_HAS_NOTHROW_COPY; - break; - case RID_HAS_TRIVIAL_ASSIGN: - kind = CPTK_HAS_TRIVIAL_ASSIGN; - break; - case RID_HAS_TRIVIAL_CONSTRUCTOR: - kind = CPTK_HAS_TRIVIAL_CONSTRUCTOR; - break; - case RID_HAS_TRIVIAL_COPY: - kind = CPTK_HAS_TRIVIAL_COPY; - break; - case RID_HAS_TRIVIAL_DESTRUCTOR: - kind = CPTK_HAS_TRIVIAL_DESTRUCTOR; - break; - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: - kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS; - break; - case RID_HAS_VIRTUAL_DESTRUCTOR: - kind = CPTK_HAS_VIRTUAL_DESTRUCTOR; - break; - case RID_IS_ABSTRACT: - kind = CPTK_IS_ABSTRACT; - break; - case RID_IS_AGGREGATE: - kind = CPTK_IS_AGGREGATE; - break; - case RID_IS_BASE_OF: - kind = CPTK_IS_BASE_OF; - binary = true; - break; - case RID_IS_CLASS: - kind = CPTK_IS_CLASS; - break; - case RID_IS_EMPTY: - kind = CPTK_IS_EMPTY; - break; - case RID_IS_ENUM: - kind = CPTK_IS_ENUM; - break; - case RID_IS_FINAL: - kind = CPTK_IS_FINAL; - break; - case RID_IS_LAYOUT_COMPATIBLE: - kind = CPTK_IS_LAYOUT_COMPATIBLE; - binary = true; - break; - case RID_IS_LITERAL_TYPE: - kind = CPTK_IS_LITERAL_TYPE; - break; - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: - kind = CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF; - binary = true; - break; - case RID_IS_POD: - kind = CPTK_IS_POD; - break; - case RID_IS_POLYMORPHIC: - kind = CPTK_IS_POLYMORPHIC; - break; - case RID_IS_SAME_AS: - kind = CPTK_IS_SAME_AS; - binary = true; - break; - case RID_IS_STD_LAYOUT: - kind = CPTK_IS_STD_LAYOUT; - break; - case RID_IS_TRIVIAL: - kind = CPTK_IS_TRIVIAL; - break; - case RID_IS_TRIVIALLY_ASSIGNABLE: - kind = CPTK_IS_TRIVIALLY_ASSIGNABLE; - binary = true; - break; - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: - kind = CPTK_IS_TRIVIALLY_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_TRIVIALLY_COPYABLE: - kind = CPTK_IS_TRIVIALLY_COPYABLE; - break; - case RID_IS_UNION: - kind = CPTK_IS_UNION; - break; - case RID_UNDERLYING_TYPE: - kind = CPTK_UNDERLYING_TYPE; - type = true; - break; - case RID_BASES: - kind = CPTK_BASES; - break; - case RID_DIRECT_BASES: - kind = CPTK_DIRECT_BASES; - break; - case RID_IS_ASSIGNABLE: - kind = CPTK_IS_ASSIGNABLE; - binary = true; - break; - case RID_IS_CONSTRUCTIBLE: - kind = CPTK_IS_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_NOTHROW_ASSIGNABLE: - kind = CPTK_IS_NOTHROW_ASSIGNABLE; - binary = true; - break; - case RID_IS_NOTHROW_CONSTRUCTIBLE: - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_CONVERTIBLE: - kind = CPTK_IS_CONVERTIBLE; - binary = true; - break; - case RID_IS_NOTHROW_CONVERTIBLE: - kind = CPTK_IS_NOTHROW_CONVERTIBLE; - binary = true; - break; - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: - kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; - binary = true; - break; - case RID_REF_CONVERTS_FROM_TEMPORARY: - kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; - binary = true; - break; - case RID_REMOVE_CV: - kind = CPTK_REMOVE_CV; - type = true; - break; - case RID_REMOVE_REFERENCE: - kind = CPTK_REMOVE_REFERENCE; - type = true; - break; - case RID_REMOVE_CVREF: - kind = CPTK_REMOVE_CVREF; - type = true; +#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 (); } @@ -19881,10 +19716,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, return type; - case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp-trait.def" +#undef DEFTRAIT_TYPE type = cp_parser_trait (parser, token->keyword); if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type, @@ -19893,14 +19728,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, return type; - case RID_BASES: - case RID_DIRECT_BASES: - type = cp_parser_trait (parser, token->keyword); - if (decl_specs) - cp_parser_set_decl_spec_type (decl_specs, type, - token, - /*type_definition_p=*/false); - return type; default: break; }
On 9/30/22 11:14, Patrick Palka wrote: > On Thu, 29 Sep 2022, Jason Merrill wrote: > >> On 9/29/22 11:05, Patrick Palka wrote: >>> Adding a new builtin trait currently involves some boilerplate (as can >>> be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and >>> CPTK_ enumerators and adding them to various switch statements across >>> many files. The exact switch statements we need to change is determined >>> by whether the proposed trait yields a type or an expression. >>> >>> This RFC patch attempts to streamline this process via a centralized >>> cp-trait.def file for declaring the important parts about a builtin trait >>> (whether it yields a type or an expression, its code, its spelling and >>> its arity) and using this file to automate away the switch statement >>> addition boilerplate. It also converts 9 traits to use this approach >>> by way of example (we can convert all the traits once the design is >>> settled). >>> >>> After this change, the process of adding a new builtin trait is just >>> (modulo tests): declare it in cp-trait.def, define its behavior in >>> finish_trait_type/expr, and handle it in diagnose_trait_expr if it's >>> an expression-yielding trait (this last step is unfortunate but since >>> the switch has no default case, we'll at least get a diagnostic if we >>> forget to do it). >>> >>> Does this look like a good approach? >> >> OK. > > Thanks a lot, I committed the following (which migrates all the > C++-specific traits to the new approach): > > -- >8 -- > > Subject: [PATCH] c++: streamline built-in trait addition process > > Adding a new built-in trait currently involves manual boilerplate > consisting of defining an rid enumerator for the identifier as well as a > corresponding cp_trait_kind enumerator and handling them in various switch > statements, the exact set of which depends on whether the proposed trait > yields (and thus is recognized as) a type or an expression. > > To streamline the process, this patch adds a central cp-trait.def file > that tabulates the essential details about each built-in trait (whether > it yields a type or an expression, its code, its spelling and its arity) > and uses this file to automate away the manual boilerplate. It also > migrates all the existing C++-specific built-in traits to use this > approach. > > After this change, adding a new built-in trait just entails declaring > it in cp-trait.def and defining its behavior in finish_trait_expr/type > (and handling it in diagnose_trait_expr, if it's an expression-yielding > trait). > > gcc/c-family/ChangeLog: > > * c-common.cc (c_common_reswords): Use cp/cp-trait.def to handle > C++ traits. > * c-common.h (enum rid): Likewise. > > gcc/cp/ChangeLog: > > * constraint.cc (diagnose_trait_expr): Likewise. > * cp-objcp-common.cc (names_builtin_p): Likewise. > * cp-tree.h (enum cp_trait_kind): Likewise. > * cxx-pretty-print.cc (pp_cxx_trait): Likewise. > * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. > (cp_parser_primary_expression): Likewise. > (cp_parser_trait): Likewise. > (cp_parser_simple_type_specifier): Likewise. > * cp-trait.def: New file. > --- > gcc/c-family/c-common.cc | 54 ++------- > gcc/c-family/c-common.h | 33 ++---- > gcc/cp/constraint.cc | 12 +- > gcc/cp/cp-objcp-common.cc | 44 +------- > gcc/cp/cp-trait.def | 106 ++++++++++++++++++ > gcc/cp/cp-tree.h | 46 +------- > gcc/cp/cxx-pretty-print.cc | 126 +-------------------- > gcc/cp/parser.cc | 217 ++++--------------------------------- > 8 files changed, 161 insertions(+), 477 deletions(-) > create mode 100644 gcc/cp/cp-trait.def > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > index 6e0af863a49..3c60a89bfe2 100644 > --- a/gcc/c-family/c-common.cc > +++ b/gcc/c-family/c-common.cc > @@ -378,7 +378,6 @@ const struct c_common_resword c_common_reswords[] = > { "__attribute", RID_ATTRIBUTE, 0 }, > { "__attribute__", RID_ATTRIBUTE, 0 }, > { "__auto_type", RID_AUTO_TYPE, D_CONLY }, > - { "__bases", RID_BASES, D_CXXONLY }, > { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY }, > { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY }, > { "__builtin_call_with_static_chain", > @@ -401,44 +400,12 @@ const struct c_common_resword c_common_reswords[] = > { "__const__", RID_CONST, 0 }, > { "__constinit", RID_CONSTINIT, D_CXXONLY }, > { "__decltype", RID_DECLTYPE, D_CXXONLY }, > - { "__direct_bases", RID_DIRECT_BASES, D_CXXONLY }, > { "__extension__", RID_EXTENSION, 0 }, > { "__func__", RID_C99_FUNCTION_NAME, 0 }, > - { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, > - { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, > - { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, > - { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, > - { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, > - { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, > - { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, > - { "__has_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, > - D_CXXONLY }, > - { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, > { "__imag", RID_IMAGPART, 0 }, > { "__imag__", RID_IMAGPART, 0 }, > { "__inline", RID_INLINE, 0 }, > { "__inline__", RID_INLINE, 0 }, > - { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, > - { "__is_aggregate", RID_IS_AGGREGATE, D_CXXONLY }, > - { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, > - { "__is_class", RID_IS_CLASS, D_CXXONLY }, > - { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, > - { "__is_enum", RID_IS_ENUM, D_CXXONLY }, > - { "__is_final", RID_IS_FINAL, D_CXXONLY }, > - { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, > - { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, > - { "__is_pointer_interconvertible_base_of", > - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, > - { "__is_pod", RID_IS_POD, D_CXXONLY }, > - { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, > - { "__is_same", RID_IS_SAME_AS, D_CXXONLY }, > - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, > - { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, > - { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, > - { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY }, > - { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY }, > - { "__is_union", RID_IS_UNION, D_CXXONLY }, > { "__label__", RID_LABEL, 0 }, > { "__null", RID_NULL, 0 }, > { "__real", RID_REALPART, 0 }, > @@ -453,7 +420,6 @@ const struct c_common_resword c_common_reswords[] = > { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, > { "__typeof", RID_TYPEOF, 0 }, > { "__typeof__", RID_TYPEOF, 0 }, > - { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, > { "__volatile", RID_VOLATILE, 0 }, > { "__volatile__", RID_VOLATILE, 0 }, > { "__GIMPLE", RID_GIMPLE, D_CONLY }, > @@ -537,19 +503,13 @@ const struct c_common_resword c_common_reswords[] = > { "volatile", RID_VOLATILE, 0 }, > { "wchar_t", RID_WCHAR, D_CXXONLY }, > { "while", RID_WHILE, 0 }, > - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, > - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, > - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, > - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, > - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, > - { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, > - D_CXXONLY }, > - { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, > - D_CXXONLY }, > - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, > - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, > - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, > + > +#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_AS, D_CXXONLY }, > > /* C++ transactional memory. */ > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index d5c98d306ce..5f470d94f4a 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -163,31 +163,14 @@ enum rid > RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, > > /* C++ extensions */ > - RID_ADDRESSOF, RID_BASES, > - RID_BUILTIN_LAUNDER, RID_DIRECT_BASES, > - RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, > - RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, > - RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, > - RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, > - RID_HAS_VIRTUAL_DESTRUCTOR, RID_BUILTIN_BIT_CAST, > - RID_IS_ABSTRACT, RID_IS_AGGREGATE, > - RID_IS_BASE_OF, RID_IS_CLASS, > - RID_IS_EMPTY, RID_IS_ENUM, > - RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, > - RID_IS_LITERAL_TYPE, > - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, > - RID_IS_POD, RID_IS_POLYMORPHIC, > - RID_IS_SAME_AS, > - RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, > - RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, > - RID_IS_TRIVIALLY_COPYABLE, > - RID_IS_UNION, RID_UNDERLYING_TYPE, > - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, > - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, > - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, > - RID_REF_CONSTRUCTS_FROM_TEMPORARY, > - RID_REF_CONVERTS_FROM_TEMPORARY, > - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, > + RID_ADDRESSOF, > + 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/constraint.cc b/gcc/cp/constraint.cc > index ca73aff3f38..f4145571d92 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -3711,13 +3711,11 @@ diagnose_trait_expr (tree expr, tree args) > inform (loc, " %qT is not a reference that binds to a temporary " > "object of type %qT (copy-initialization)", t1, t2); > break; > - case CPTK_BASES: > - case CPTK_DIRECT_BASES: > - case CPTK_UNDERLYING_TYPE: > - case CPTK_REMOVE_CV: > - case CPTK_REMOVE_REFERENCE: > - case CPTK_REMOVE_CVREF: > - /* We shouldn't see these non-expression traits. */ > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case CPTK_##CODE: > +#include "cp-trait.def" > +#undef DEFTRAIT_TYPE > + /* Type-yielding traits aren't expressions. */ > gcc_unreachable (); > /* We deliberately omit the default case so that when adding a new > trait we'll get reminded (by way of a warning) to handle it here. */ > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc > index 2d3f206b530..e4df30d9720 100644 > --- a/gcc/cp/cp-objcp-common.cc > +++ b/gcc/cp/cp-objcp-common.cc > @@ -430,46 +430,10 @@ names_builtin_p (const char *name) > case RID_BUILTIN_ASSOC_BARRIER: > case RID_BUILTIN_BIT_CAST: > case RID_OFFSETOF: > - case RID_HAS_NOTHROW_ASSIGN: > - case RID_HAS_NOTHROW_CONSTRUCTOR: > - case RID_HAS_NOTHROW_COPY: > - case RID_HAS_TRIVIAL_ASSIGN: > - case RID_HAS_TRIVIAL_CONSTRUCTOR: > - case RID_HAS_TRIVIAL_COPY: > - case RID_HAS_TRIVIAL_DESTRUCTOR: > - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: > - case RID_HAS_VIRTUAL_DESTRUCTOR: > - case RID_IS_ABSTRACT: > - case RID_IS_AGGREGATE: > - case RID_IS_BASE_OF: > - case RID_IS_CLASS: > - case RID_IS_EMPTY: > - case RID_IS_ENUM: > - case RID_IS_FINAL: > - case RID_IS_LAYOUT_COMPATIBLE: > - case RID_IS_LITERAL_TYPE: > - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: > - case RID_IS_POD: > - case RID_IS_POLYMORPHIC: > - case RID_IS_SAME_AS: > - case RID_IS_STD_LAYOUT: > - case RID_IS_TRIVIAL: > - case RID_IS_TRIVIALLY_ASSIGNABLE: > - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > - case RID_IS_TRIVIALLY_COPYABLE: > - case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - case RID_UNDERLYING_TYPE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > - case RID_REF_CONVERTS_FROM_TEMPORARY: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#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.def b/gcc/cp/cp-trait.def > new file mode 100644 > index 00000000000..922348a1659 > --- /dev/null > +++ b/gcc/cp/cp-trait.def > @@ -0,0 +1,106 @@ > +/* This file contains the definitions for C++-specific built-in traits. > + > + Copyright The GNU Toolchain Authors. > + > + 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/>. */ > + > +/* Add a DEFTRAIT_EXPR (CODE, NAME, N) line to this file to define an > + expression-yielding built-in trait that has internal code name CODE, is > + spelled as NAME and takes N type arguments (where N is either 1, 2, or > + the special value -1 which denotes that it takes at least one argument). > + Such traits are represented as TRAIT_EXPR tree whose TRAIT_EXPR_KIND is > + CPTK_CODE. Define the behavior of the trait in finish_trait_expr. */ > + > +/* Add a DEFTRAIT_TYPE (CODE, NAME, N) line to this file to define a > + type-yielding built-in trait as described above. Such traits are > + generally represented as a TRAIT_TYPE tree whose TRAIT_TYPE_KIND is > + CPTK_CODE (exceptions are BASES and DIRECT_BASES below). Define the > + behavior of the trait in finish_trait_type. */ > + > +#ifdef DEFTRAIT > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_EXPR > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) > +#define DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifndef DEFTRAIT_TYPE > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) > +#define DEFTRAIT_TYPE_DEFAULTED > +#endif > + > +DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1) > +DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1) > +DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1) > +DEFTRAIT_EXPR (HAS_TRIVIAL_ASSIGN, "__has_trivial_assign", 1) > +DEFTRAIT_EXPR (HAS_TRIVIAL_CONSTRUCTOR, "__has_trivial_constructor", 1) > +DEFTRAIT_EXPR (HAS_TRIVIAL_COPY, "__has_trivial_copy", 1) > +DEFTRAIT_EXPR (HAS_TRIVIAL_DESTRUCTOR, "__has_trivial_destructor", 1) > +DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, "__has_unique_object_representations", 1) > +DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1) > +DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1) > +DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1) > +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) > +DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2) > +DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) > +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) > +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) > +DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1) > +DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1) > +DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1) > +DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2) > +DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1) > +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) > +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) > +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) > +DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) > +DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) > +DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) > +DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) Can we make the code and name agree? I don't feel strongly about which way. > +DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1) > +DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1) > +DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2) > +DEFTRAIT_EXPR (IS_TRIVIALLY_CONSTRUCTIBLE, "__is_trivially_constructible", -1) > +DEFTRAIT_EXPR (IS_TRIVIALLY_COPYABLE, "__is_trivially_copyable", 1) > +DEFTRAIT_EXPR (IS_UNION, "__is_union", 1) > +DEFTRAIT_EXPR (REF_CONSTRUCTS_FROM_TEMPORARY, "__reference_constructs_from_temporary", 2) > +DEFTRAIT_EXPR (REF_CONVERTS_FROM_TEMPORARY, "__reference_converts_from_temporary", 2) > + > +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) > +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) > +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) > +DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1) > + > +/* These traits yield a type pack, not a type, and are represented by > + cp_parser_trait as a special BASES tree instead of a TRAIT_TYPE tree. */ > +DEFTRAIT_TYPE (BASES, "__bases", 1) > +DEFTRAIT_TYPE (DIRECT_BASES, "__direct_bases", 1) > + > +#ifdef DEFTRAIT_EXPR_DEFAULTED > +#undef DEFTRAIT_EXPR > +#undef DEFTRAIT_EXPR_DEFAULTED > +#endif > + > +#ifdef DEFTRAIT_TYPE_DEFAULTED > +#undef DEFTRAIT_TYPE > +#undef DEFTRAIT_TYPE_DEFAULTED > +#endif > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h > index d696fd54a7a..67aea9653e3 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -1374,48 +1374,10 @@ struct GTY (()) tree_argument_pack_select { > > enum cp_trait_kind > { > - CPTK_BASES, > - CPTK_DIRECT_BASES, > - CPTK_HAS_NOTHROW_ASSIGN, > - CPTK_HAS_NOTHROW_CONSTRUCTOR, > - CPTK_HAS_NOTHROW_COPY, > - CPTK_HAS_TRIVIAL_ASSIGN, > - CPTK_HAS_TRIVIAL_CONSTRUCTOR, > - CPTK_HAS_TRIVIAL_COPY, > - CPTK_HAS_TRIVIAL_DESTRUCTOR, > - CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, > - CPTK_HAS_VIRTUAL_DESTRUCTOR, > - CPTK_IS_ABSTRACT, > - CPTK_IS_AGGREGATE, > - CPTK_IS_BASE_OF, > - CPTK_IS_CLASS, > - CPTK_IS_EMPTY, > - CPTK_IS_ENUM, > - CPTK_IS_FINAL, > - CPTK_IS_LAYOUT_COMPATIBLE, > - CPTK_IS_LITERAL_TYPE, > - CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, > - CPTK_IS_POD, > - CPTK_IS_POLYMORPHIC, > - CPTK_IS_SAME_AS, > - CPTK_IS_STD_LAYOUT, > - CPTK_IS_TRIVIAL, > - CPTK_IS_TRIVIALLY_ASSIGNABLE, > - CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, > - CPTK_IS_TRIVIALLY_COPYABLE, > - CPTK_IS_UNION, > - CPTK_UNDERLYING_TYPE, > - CPTK_IS_ASSIGNABLE, > - CPTK_IS_CONSTRUCTIBLE, > - CPTK_IS_NOTHROW_ASSIGNABLE, > - CPTK_IS_NOTHROW_CONSTRUCTIBLE, > - CPTK_IS_CONVERTIBLE, > - CPTK_IS_NOTHROW_CONVERTIBLE, > - CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, > - CPTK_REF_CONVERTS_FROM_TEMPORARY, > - CPTK_REMOVE_CV, > - CPTK_REMOVE_REFERENCE, > - CPTK_REMOVE_CVREF, > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + CPTK_##CODE, > +#include "cp-trait.def" > +#undef DEFTRAIT > }; > > /* The types that we are processing. */ > diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc > index b91615439e4..8ca1b8f234a 100644 > --- a/gcc/cp/cxx-pretty-print.cc > +++ b/gcc/cp/cxx-pretty-print.cc > @@ -2617,128 +2617,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) > > switch (kind) > { > - case CPTK_HAS_NOTHROW_ASSIGN: > - pp_cxx_ws_string (pp, "__has_nothrow_assign"); > +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ > + case CPTK_##CODE: \ > + pp_cxx_ws_string (pp, NAME); \ > break; > - case CPTK_HAS_TRIVIAL_ASSIGN: > - pp_cxx_ws_string (pp, "__has_trivial_assign"); > - break; > - case CPTK_HAS_NOTHROW_CONSTRUCTOR: > - pp_cxx_ws_string (pp, "__has_nothrow_constructor"); > - break; > - case CPTK_HAS_TRIVIAL_CONSTRUCTOR: > - pp_cxx_ws_string (pp, "__has_trivial_constructor"); > - break; > - case CPTK_HAS_NOTHROW_COPY: > - pp_cxx_ws_string (pp, "__has_nothrow_copy"); > - break; > - case CPTK_HAS_TRIVIAL_COPY: > - pp_cxx_ws_string (pp, "__has_trivial_copy"); > - break; > - case CPTK_HAS_TRIVIAL_DESTRUCTOR: > - pp_cxx_ws_string (pp, "__has_trivial_destructor"); > - break; > - case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: > - pp_cxx_ws_string (pp, "__has_unique_object_representations"); > - break; > - case CPTK_HAS_VIRTUAL_DESTRUCTOR: > - pp_cxx_ws_string (pp, "__has_virtual_destructor"); > - break; > - case CPTK_IS_ABSTRACT: > - pp_cxx_ws_string (pp, "__is_abstract"); > - break; > - case CPTK_IS_AGGREGATE: > - pp_cxx_ws_string (pp, "__is_aggregate"); > - break; > - case CPTK_IS_BASE_OF: > - pp_cxx_ws_string (pp, "__is_base_of"); > - break; > - case CPTK_IS_CLASS: > - pp_cxx_ws_string (pp, "__is_class"); > - break; > - case CPTK_IS_EMPTY: > - pp_cxx_ws_string (pp, "__is_empty"); > - break; > - case CPTK_IS_ENUM: > - pp_cxx_ws_string (pp, "__is_enum"); > - break; > - case CPTK_IS_FINAL: > - pp_cxx_ws_string (pp, "__is_final"); > - break; > - case CPTK_IS_LAYOUT_COMPATIBLE: > - pp_cxx_ws_string (pp, "__is_layout_compatible"); > - break; > - case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: > - pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); > - break; > - case CPTK_IS_POD: > - pp_cxx_ws_string (pp, "__is_pod"); > - break; > - case CPTK_IS_POLYMORPHIC: > - pp_cxx_ws_string (pp, "__is_polymorphic"); > - break; > - case CPTK_IS_SAME_AS: > - pp_cxx_ws_string (pp, "__is_same"); > - break; > - case CPTK_IS_STD_LAYOUT: > - pp_cxx_ws_string (pp, "__is_std_layout"); > - break; > - case CPTK_IS_TRIVIAL: > - pp_cxx_ws_string (pp, "__is_trivial"); > - break; > - case CPTK_IS_TRIVIALLY_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_trivially_assignable"); > - break; > - case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_trivially_constructible"); > - break; > - case CPTK_IS_TRIVIALLY_COPYABLE: > - pp_cxx_ws_string (pp, "__is_trivially_copyable"); > - break; > - case CPTK_IS_UNION: > - pp_cxx_ws_string (pp, "__is_union"); > - break; > - case CPTK_IS_LITERAL_TYPE: > - pp_cxx_ws_string (pp, "__is_literal_type"); > - break; > - case CPTK_IS_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_assignable"); > - break; > - case CPTK_IS_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_constructible"); > - break; > - case CPTK_IS_NOTHROW_ASSIGNABLE: > - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); > - break; > - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); > - break; > - case CPTK_IS_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_convertible"); > - break; > - case CPTK_IS_NOTHROW_CONVERTIBLE: > - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); > - break; > - case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: > - pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); > - break; > - case CPTK_REF_CONVERTS_FROM_TEMPORARY: > - pp_cxx_ws_string (pp, "__reference_converts_from_temporary"); > - break; > - case CPTK_UNDERLYING_TYPE: > - pp_cxx_ws_string (pp, "__underlying_type"); > - break; > - case CPTK_REMOVE_CV: > - pp_cxx_ws_string (pp, "__remove_cv"); > - break; > - case CPTK_REMOVE_REFERENCE: > - pp_cxx_ws_string (pp, "__remove_reference"); > - break; > - case CPTK_REMOVE_CVREF: > - pp_cxx_ws_string (pp, "__remove_cvref"); > - break; > - default: > - gcc_unreachable (); > +#include "cp-trait.def" > +#undef DEFTRAIT > } > > pp_cxx_left_paren (pp); > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index d592d783250..8d0e0fa1b87 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -1146,16 +1146,18 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) > case RID_TYPEOF: > /* C++11 extensions. */ > case RID_DECLTYPE: > - case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > case RID_CONSTEXPR: > /* C++20 extensions. */ > case RID_CONSTINIT: > case RID_CONSTEVAL: > return true; > > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp-trait.def" > +#undef DEFTRAIT_TYPE > + return true; > + > default: > if (keyword >= RID_FIRST_INT_N > && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS > @@ -5895,42 +5897,10 @@ cp_parser_primary_expression (cp_parser *parser, > case RID_OFFSETOF: > return cp_parser_builtin_offsetof (parser); > > - case RID_HAS_NOTHROW_ASSIGN: > - case RID_HAS_NOTHROW_CONSTRUCTOR: > - case RID_HAS_NOTHROW_COPY: > - case RID_HAS_TRIVIAL_ASSIGN: > - case RID_HAS_TRIVIAL_CONSTRUCTOR: > - case RID_HAS_TRIVIAL_COPY: > - case RID_HAS_TRIVIAL_DESTRUCTOR: > - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: > - case RID_HAS_VIRTUAL_DESTRUCTOR: > - case RID_IS_ABSTRACT: > - case RID_IS_AGGREGATE: > - case RID_IS_BASE_OF: > - case RID_IS_CLASS: > - case RID_IS_EMPTY: > - case RID_IS_ENUM: > - case RID_IS_FINAL: > - case RID_IS_LAYOUT_COMPATIBLE: > - case RID_IS_LITERAL_TYPE: > - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: > - case RID_IS_POD: > - case RID_IS_POLYMORPHIC: > - case RID_IS_SAME_AS: > - case RID_IS_STD_LAYOUT: > - case RID_IS_TRIVIAL: > - case RID_IS_TRIVIALLY_ASSIGNABLE: > - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > - case RID_IS_TRIVIALLY_COPYABLE: > - case RID_IS_UNION: > - case RID_IS_ASSIGNABLE: > - case RID_IS_CONSTRUCTIBLE: > - case RID_IS_NOTHROW_ASSIGNABLE: > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - case RID_IS_CONVERTIBLE: > - case RID_IS_NOTHROW_CONVERTIBLE: > - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > - case RID_REF_CONVERTS_FROM_TEMPORARY: > +#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 > @@ -10898,150 +10868,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) > > switch (keyword) > { > - case RID_HAS_NOTHROW_ASSIGN: > - kind = CPTK_HAS_NOTHROW_ASSIGN; > - break; > - case RID_HAS_NOTHROW_CONSTRUCTOR: > - kind = CPTK_HAS_NOTHROW_CONSTRUCTOR; > - break; > - case RID_HAS_NOTHROW_COPY: > - kind = CPTK_HAS_NOTHROW_COPY; > - break; > - case RID_HAS_TRIVIAL_ASSIGN: > - kind = CPTK_HAS_TRIVIAL_ASSIGN; > - break; > - case RID_HAS_TRIVIAL_CONSTRUCTOR: > - kind = CPTK_HAS_TRIVIAL_CONSTRUCTOR; > - break; > - case RID_HAS_TRIVIAL_COPY: > - kind = CPTK_HAS_TRIVIAL_COPY; > - break; > - case RID_HAS_TRIVIAL_DESTRUCTOR: > - kind = CPTK_HAS_TRIVIAL_DESTRUCTOR; > - break; > - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: > - kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS; > - break; > - case RID_HAS_VIRTUAL_DESTRUCTOR: > - kind = CPTK_HAS_VIRTUAL_DESTRUCTOR; > - break; > - case RID_IS_ABSTRACT: > - kind = CPTK_IS_ABSTRACT; > - break; > - case RID_IS_AGGREGATE: > - kind = CPTK_IS_AGGREGATE; > - break; > - case RID_IS_BASE_OF: > - kind = CPTK_IS_BASE_OF; > - binary = true; > - break; > - case RID_IS_CLASS: > - kind = CPTK_IS_CLASS; > - break; > - case RID_IS_EMPTY: > - kind = CPTK_IS_EMPTY; > - break; > - case RID_IS_ENUM: > - kind = CPTK_IS_ENUM; > - break; > - case RID_IS_FINAL: > - kind = CPTK_IS_FINAL; > - break; > - case RID_IS_LAYOUT_COMPATIBLE: > - kind = CPTK_IS_LAYOUT_COMPATIBLE; > - binary = true; > - break; > - case RID_IS_LITERAL_TYPE: > - kind = CPTK_IS_LITERAL_TYPE; > - break; > - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: > - kind = CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF; > - binary = true; > - break; > - case RID_IS_POD: > - kind = CPTK_IS_POD; > - break; > - case RID_IS_POLYMORPHIC: > - kind = CPTK_IS_POLYMORPHIC; > - break; > - case RID_IS_SAME_AS: > - kind = CPTK_IS_SAME_AS; > - binary = true; > - break; > - case RID_IS_STD_LAYOUT: > - kind = CPTK_IS_STD_LAYOUT; > - break; > - case RID_IS_TRIVIAL: > - kind = CPTK_IS_TRIVIAL; > - break; > - case RID_IS_TRIVIALLY_ASSIGNABLE: > - kind = CPTK_IS_TRIVIALLY_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > - kind = CPTK_IS_TRIVIALLY_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_TRIVIALLY_COPYABLE: > - kind = CPTK_IS_TRIVIALLY_COPYABLE; > - break; > - case RID_IS_UNION: > - kind = CPTK_IS_UNION; > - break; > - case RID_UNDERLYING_TYPE: > - kind = CPTK_UNDERLYING_TYPE; > - type = true; > - break; > - case RID_BASES: > - kind = CPTK_BASES; > - break; > - case RID_DIRECT_BASES: > - kind = CPTK_DIRECT_BASES; > - break; > - case RID_IS_ASSIGNABLE: > - kind = CPTK_IS_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_CONSTRUCTIBLE: > - kind = CPTK_IS_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_NOTHROW_ASSIGNABLE: > - kind = CPTK_IS_NOTHROW_ASSIGNABLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; > - variadic = true; > - break; > - case RID_IS_CONVERTIBLE: > - kind = CPTK_IS_CONVERTIBLE; > - binary = true; > - break; > - case RID_IS_NOTHROW_CONVERTIBLE: > - kind = CPTK_IS_NOTHROW_CONVERTIBLE; > - binary = true; > - break; > - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > - kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; > - binary = true; > - break; > - case RID_REF_CONVERTS_FROM_TEMPORARY: > - kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; > - binary = true; > - break; > - case RID_REMOVE_CV: > - kind = CPTK_REMOVE_CV; > - type = true; > - break; > - case RID_REMOVE_REFERENCE: > - kind = CPTK_REMOVE_REFERENCE; > - type = true; > - break; > - case RID_REMOVE_CVREF: > - kind = CPTK_REMOVE_CVREF; > - type = true; > +#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 (); > } > @@ -19881,10 +19716,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, > > return type; > > - case RID_UNDERLYING_TYPE: > - case RID_REMOVE_CV: > - case RID_REMOVE_REFERENCE: > - case RID_REMOVE_CVREF: > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > + case RID_##CODE: > +#include "cp-trait.def" > +#undef DEFTRAIT_TYPE > type = cp_parser_trait (parser, token->keyword); > if (decl_specs) > cp_parser_set_decl_spec_type (decl_specs, type, > @@ -19893,14 +19728,6 @@ cp_parser_simple_type_specifier (cp_parser* parser, > > return type; > > - case RID_BASES: > - case RID_DIRECT_BASES: > - type = cp_parser_trait (parser, token->keyword); > - if (decl_specs) > - cp_parser_set_decl_spec_type (decl_specs, type, > - token, > - /*type_definition_p=*/false); > - return type; > default: > break; > }
On Fri, 30 Sep 2022, Jason Merrill wrote: > On 9/30/22 11:14, Patrick Palka wrote: > > On Thu, 29 Sep 2022, Jason Merrill wrote: > > > > > On 9/29/22 11:05, Patrick Palka wrote: > > > > Adding a new builtin trait currently involves some boilerplate (as can > > > > be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and > > > > CPTK_ enumerators and adding them to various switch statements across > > > > many files. The exact switch statements we need to change is determined > > > > by whether the proposed trait yields a type or an expression. > > > > > > > > This RFC patch attempts to streamline this process via a centralized > > > > cp-trait.def file for declaring the important parts about a builtin > > > > trait > > > > (whether it yields a type or an expression, its code, its spelling and > > > > its arity) and using this file to automate away the switch statement > > > > addition boilerplate. It also converts 9 traits to use this approach > > > > by way of example (we can convert all the traits once the design is > > > > settled). > > > > > > > > After this change, the process of adding a new builtin trait is just > > > > (modulo tests): declare it in cp-trait.def, define its behavior in > > > > finish_trait_type/expr, and handle it in diagnose_trait_expr if it's > > > > an expression-yielding trait (this last step is unfortunate but since > > > > the switch has no default case, we'll at least get a diagnostic if we > > > > forget to do it). > > > > > > > > Does this look like a good approach? > > > > > > OK. > > > > Thanks a lot, I committed the following (which migrates all the > > C++-specific traits to the new approach): > > > > -- >8 -- > > > > Subject: [PATCH] c++: streamline built-in trait addition process > > > > Adding a new built-in trait currently involves manual boilerplate > > consisting of defining an rid enumerator for the identifier as well as a > > corresponding cp_trait_kind enumerator and handling them in various switch > > statements, the exact set of which depends on whether the proposed trait > > yields (and thus is recognized as) a type or an expression. > > > > To streamline the process, this patch adds a central cp-trait.def file > > that tabulates the essential details about each built-in trait (whether > > it yields a type or an expression, its code, its spelling and its arity) > > and uses this file to automate away the manual boilerplate. It also > > migrates all the existing C++-specific built-in traits to use this > > approach. > > > > After this change, adding a new built-in trait just entails declaring > > it in cp-trait.def and defining its behavior in finish_trait_expr/type > > (and handling it in diagnose_trait_expr, if it's an expression-yielding > > trait). > > > > gcc/c-family/ChangeLog: > > > > * c-common.cc (c_common_reswords): Use cp/cp-trait.def to handle > > C++ traits. > > * c-common.h (enum rid): Likewise. > > > > gcc/cp/ChangeLog: > > > > * constraint.cc (diagnose_trait_expr): Likewise. > > * cp-objcp-common.cc (names_builtin_p): Likewise. > > * cp-tree.h (enum cp_trait_kind): Likewise. > > * cxx-pretty-print.cc (pp_cxx_trait): Likewise. > > * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. > > (cp_parser_primary_expression): Likewise. > > (cp_parser_trait): Likewise. > > (cp_parser_simple_type_specifier): Likewise. > > * cp-trait.def: New file. > > --- > > gcc/c-family/c-common.cc | 54 ++------- > > gcc/c-family/c-common.h | 33 ++---- > > gcc/cp/constraint.cc | 12 +- > > gcc/cp/cp-objcp-common.cc | 44 +------- > > gcc/cp/cp-trait.def | 106 ++++++++++++++++++ > > gcc/cp/cp-tree.h | 46 +------- > > gcc/cp/cxx-pretty-print.cc | 126 +-------------------- > > gcc/cp/parser.cc | 217 ++++--------------------------------- > > 8 files changed, 161 insertions(+), 477 deletions(-) > > create mode 100644 gcc/cp/cp-trait.def > > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > > index 6e0af863a49..3c60a89bfe2 100644 > > --- a/gcc/c-family/c-common.cc > > +++ b/gcc/c-family/c-common.cc > > @@ -378,7 +378,6 @@ const struct c_common_resword c_common_reswords[] = > > { "__attribute", RID_ATTRIBUTE, 0 }, > > { "__attribute__", RID_ATTRIBUTE, 0 }, > > { "__auto_type", RID_AUTO_TYPE, D_CONLY }, > > - { "__bases", RID_BASES, D_CXXONLY }, > > { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY }, > > { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY }, > > { "__builtin_call_with_static_chain", > > @@ -401,44 +400,12 @@ const struct c_common_resword c_common_reswords[] = > > { "__const__", RID_CONST, 0 }, > > { "__constinit", RID_CONSTINIT, D_CXXONLY }, > > { "__decltype", RID_DECLTYPE, D_CXXONLY }, > > - { "__direct_bases", RID_DIRECT_BASES, D_CXXONLY }, > > { "__extension__", RID_EXTENSION, 0 }, > > { "__func__", RID_C99_FUNCTION_NAME, 0 }, > > - { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, > > - { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, > > - { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, > > - { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, > > - { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, > > - { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, > > - { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, > > - { "__has_unique_object_representations", > > RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, > > - D_CXXONLY }, > > - { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, > > { "__imag", RID_IMAGPART, 0 }, > > { "__imag__", RID_IMAGPART, 0 }, > > { "__inline", RID_INLINE, 0 }, > > { "__inline__", RID_INLINE, 0 }, > > - { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, > > - { "__is_aggregate", RID_IS_AGGREGATE, D_CXXONLY }, > > - { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, > > - { "__is_class", RID_IS_CLASS, D_CXXONLY }, > > - { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, > > - { "__is_enum", RID_IS_ENUM, D_CXXONLY }, > > - { "__is_final", RID_IS_FINAL, D_CXXONLY }, > > - { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, > > - { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, > > - { "__is_pointer_interconvertible_base_of", > > - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, > > - { "__is_pod", RID_IS_POD, D_CXXONLY }, > > - { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, > > - { "__is_same", RID_IS_SAME_AS, D_CXXONLY }, > > - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, > > - { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, > > - { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, > > - { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY }, > > - { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, > > D_CXXONLY }, > > - { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY }, > > - { "__is_union", RID_IS_UNION, D_CXXONLY }, > > { "__label__", RID_LABEL, 0 }, > > { "__null", RID_NULL, 0 }, > > { "__real", RID_REALPART, 0 }, > > @@ -453,7 +420,6 @@ const struct c_common_resword c_common_reswords[] = > > { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, > > { "__typeof", RID_TYPEOF, 0 }, > > { "__typeof__", RID_TYPEOF, 0 }, > > - { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, > > { "__volatile", RID_VOLATILE, 0 }, > > { "__volatile__", RID_VOLATILE, 0 }, > > { "__GIMPLE", RID_GIMPLE, D_CONLY }, > > @@ -537,19 +503,13 @@ const struct c_common_resword c_common_reswords[] = > > { "volatile", RID_VOLATILE, 0 }, > > { "wchar_t", RID_WCHAR, D_CXXONLY }, > > { "while", RID_WHILE, 0 }, > > - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, > > - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, > > - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, > > - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY > > }, > > - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, > > - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, > > - { "__reference_constructs_from_temporary", > > RID_REF_CONSTRUCTS_FROM_TEMPORARY, > > - D_CXXONLY }, > > - { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, > > - D_CXXONLY }, > > - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, > > - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, > > - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, > > + > > +#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_AS, D_CXXONLY }, > > /* C++ transactional memory. */ > > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > > index d5c98d306ce..5f470d94f4a 100644 > > --- a/gcc/c-family/c-common.h > > +++ b/gcc/c-family/c-common.h > > @@ -163,31 +163,14 @@ enum rid > > RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, > > /* C++ extensions */ > > - RID_ADDRESSOF, RID_BASES, > > - RID_BUILTIN_LAUNDER, RID_DIRECT_BASES, > > - RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, > > - RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, > > - RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, > > - RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, > > - RID_HAS_VIRTUAL_DESTRUCTOR, RID_BUILTIN_BIT_CAST, > > - RID_IS_ABSTRACT, RID_IS_AGGREGATE, > > - RID_IS_BASE_OF, RID_IS_CLASS, > > - RID_IS_EMPTY, RID_IS_ENUM, > > - RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, > > - RID_IS_LITERAL_TYPE, > > - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, > > - RID_IS_POD, RID_IS_POLYMORPHIC, > > - RID_IS_SAME_AS, > > - RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, > > - RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, > > - RID_IS_TRIVIALLY_COPYABLE, > > - RID_IS_UNION, RID_UNDERLYING_TYPE, > > - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, > > - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, > > - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, > > - RID_REF_CONSTRUCTS_FROM_TEMPORARY, > > - RID_REF_CONVERTS_FROM_TEMPORARY, > > - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, > > + RID_ADDRESSOF, > > + 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/constraint.cc b/gcc/cp/constraint.cc > > index ca73aff3f38..f4145571d92 100644 > > --- a/gcc/cp/constraint.cc > > +++ b/gcc/cp/constraint.cc > > @@ -3711,13 +3711,11 @@ diagnose_trait_expr (tree expr, tree args) > > inform (loc, " %qT is not a reference that binds to a temporary " > > "object of type %qT (copy-initialization)", t1, t2); > > break; > > - case CPTK_BASES: > > - case CPTK_DIRECT_BASES: > > - case CPTK_UNDERLYING_TYPE: > > - case CPTK_REMOVE_CV: > > - case CPTK_REMOVE_REFERENCE: > > - case CPTK_REMOVE_CVREF: > > - /* We shouldn't see these non-expression traits. */ > > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ > > + case CPTK_##CODE: > > +#include "cp-trait.def" > > +#undef DEFTRAIT_TYPE > > + /* Type-yielding traits aren't expressions. */ > > gcc_unreachable (); > > /* We deliberately omit the default case so that when adding a new > > trait we'll get reminded (by way of a warning) to handle it here. > > */ > > diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc > > index 2d3f206b530..e4df30d9720 100644 > > --- a/gcc/cp/cp-objcp-common.cc > > +++ b/gcc/cp/cp-objcp-common.cc > > @@ -430,46 +430,10 @@ names_builtin_p (const char *name) > > case RID_BUILTIN_ASSOC_BARRIER: > > case RID_BUILTIN_BIT_CAST: > > case RID_OFFSETOF: > > - case RID_HAS_NOTHROW_ASSIGN: > > - case RID_HAS_NOTHROW_CONSTRUCTOR: > > - case RID_HAS_NOTHROW_COPY: > > - case RID_HAS_TRIVIAL_ASSIGN: > > - case RID_HAS_TRIVIAL_CONSTRUCTOR: > > - case RID_HAS_TRIVIAL_COPY: > > - case RID_HAS_TRIVIAL_DESTRUCTOR: > > - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: > > - case RID_HAS_VIRTUAL_DESTRUCTOR: > > - case RID_IS_ABSTRACT: > > - case RID_IS_AGGREGATE: > > - case RID_IS_BASE_OF: > > - case RID_IS_CLASS: > > - case RID_IS_EMPTY: > > - case RID_IS_ENUM: > > - case RID_IS_FINAL: > > - case RID_IS_LAYOUT_COMPATIBLE: > > - case RID_IS_LITERAL_TYPE: > > - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: > > - case RID_IS_POD: > > - case RID_IS_POLYMORPHIC: > > - case RID_IS_SAME_AS: > > - case RID_IS_STD_LAYOUT: > > - case RID_IS_TRIVIAL: > > - case RID_IS_TRIVIALLY_ASSIGNABLE: > > - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: > > - case RID_IS_TRIVIALLY_COPYABLE: > > - case RID_IS_UNION: > > - case RID_IS_ASSIGNABLE: > > - case RID_IS_CONSTRUCTIBLE: > > - case RID_IS_NOTHROW_ASSIGNABLE: > > - case RID_IS_NOTHROW_CONSTRUCTIBLE: > > - case RID_UNDERLYING_TYPE: > > - case RID_IS_CONVERTIBLE: > > - case RID_IS_NOTHROW_CONVERTIBLE: > > - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: > > - case RID_REF_CONVERTS_FROM_TEMPORARY: > > - case RID_REMOVE_CV: > > - case RID_REMOVE_REFERENCE: > > - case RID_REMOVE_CVREF: > > +#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.def b/gcc/cp/cp-trait.def > > new file mode 100644 > > index 00000000000..922348a1659 > > --- /dev/null > > +++ b/gcc/cp/cp-trait.def > > @@ -0,0 +1,106 @@ > > +/* This file contains the definitions for C++-specific built-in traits. > > + > > + Copyright The GNU Toolchain Authors. > > + > > + 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/>. */ > > + > > +/* Add a DEFTRAIT_EXPR (CODE, NAME, N) line to this file to define an > > + expression-yielding built-in trait that has internal code name CODE, is > > + spelled as NAME and takes N type arguments (where N is either 1, 2, or > > + the special value -1 which denotes that it takes at least one argument). > > + Such traits are represented as TRAIT_EXPR tree whose TRAIT_EXPR_KIND is > > + CPTK_CODE. Define the behavior of the trait in finish_trait_expr. */ > > + > > +/* Add a DEFTRAIT_TYPE (CODE, NAME, N) line to this file to define a > > + type-yielding built-in trait as described above. Such traits are > > + generally represented as a TRAIT_TYPE tree whose TRAIT_TYPE_KIND is > > + CPTK_CODE (exceptions are BASES and DIRECT_BASES below). Define the > > + behavior of the trait in finish_trait_type. */ > > + > > +#ifdef DEFTRAIT > > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, > > NAME, ARITY) > > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, > > ARITY) > > +#define DEFTRAIT_EXPR_DEFAULTED > > +#define DEFTRAIT_TYPE_DEFAULTED > > +#endif > > + > > +#ifndef DEFTRAIT_EXPR > > +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) > > +#define DEFTRAIT_EXPR_DEFAULTED > > +#endif > > + > > +#ifndef DEFTRAIT_TYPE > > +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) > > +#define DEFTRAIT_TYPE_DEFAULTED > > +#endif > > + > > +DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1) > > +DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1) > > +DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1) > > +DEFTRAIT_EXPR (HAS_TRIVIAL_ASSIGN, "__has_trivial_assign", 1) > > +DEFTRAIT_EXPR (HAS_TRIVIAL_CONSTRUCTOR, "__has_trivial_constructor", 1) > > +DEFTRAIT_EXPR (HAS_TRIVIAL_COPY, "__has_trivial_copy", 1) > > +DEFTRAIT_EXPR (HAS_TRIVIAL_DESTRUCTOR, "__has_trivial_destructor", 1) > > +DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, > > "__has_unique_object_representations", 1) > > +DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1) > > +DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1) > > +DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1) > > +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) > > +DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2) > > +DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) > > +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) > > +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) > > +DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1) > > +DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1) > > +DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1) > > +DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2) > > +DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1) > > +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) > > +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) > > +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) > > +DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, > > "__is_pointer_interconvertible_base_of", 2) > > +DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) > > +DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) > > +DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) > > Can we make the code and name agree? I don't feel strongly about which way. I suppose we should keep __is_same as the canonical spelling (as per PR92271), so changing the code name seems preferable. Like so? -- >8 -- Subject: [PATCH] c++: rename IS_SAME_AS trait code to IS_SAME ... to match the canonical spelling __is_same of the trait itself (also spelled as __is_same_as). gcc/c-family/ChangeLog: * c-common.cc (c_common_reswords): Use RID_IS_SAME instead of RID_IS_SAME_AS. gcc/cp/ChangeLog: * constraint.cc (diagnose_trait_expr): Use CPTK_IS_SAME instead of CPTK_IS_SAME_AS. * cp-trait.def (IS_SAME_AS): Rename to ... (IS_SAME): ... this. * pt.cc (alias_ctad_tweaks): Use CPTK_IS_SAME instead of CPTK_IS_SAME_AS. * semantics.cc (trait_expr_value): Likewise. (finish_trait_expr): Likewise. --- gcc/c-family/c-common.cc | 2 +- gcc/cp/constraint.cc | 2 +- gcc/cp/cp-trait.def | 2 +- gcc/cp/pt.cc | 2 +- gcc/cp/semantics.cc | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 3c60a89bfe2..4f9878d2695 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -509,7 +509,7 @@ const struct c_common_resword c_common_reswords[] = #include "cp/cp-trait.def" #undef DEFTRAIT /* An alias for __is_same. */ - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, + { "__is_same_as", RID_IS_SAME, D_CXXONLY }, /* C++ transactional memory. */ { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index f4145571d92..74898ca1a23 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3649,7 +3649,7 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_POLYMORPHIC: inform (loc, " %qT is not a polymorphic type", t1); break; - case CPTK_IS_SAME_AS: + case CPTK_IS_SAME: inform (loc, " %qT is not the same as %qT", t1, t2); break; case CPTK_IS_STD_LAYOUT: diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def index 922348a1659..823899a26c5 100644 --- a/gcc/cp/cp-trait.def +++ b/gcc/cp/cp-trait.def @@ -75,7 +75,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) -DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) +DEFTRAIT_EXPR (IS_SAME, "__is_same", 2) DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1) DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1) DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 258f76d6e47..bce2a777922 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30029,7 +30029,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* FIXME this should mean they don't compare as equivalent. */ || dependent_alias_template_spec_p (atype, nt_opaque)) { - tree same = finish_trait_expr (loc, CPTK_IS_SAME_AS, atype, ret); + tree same = finish_trait_expr (loc, CPTK_IS_SAME, atype, ret); ci = append_constraint (ci, same); } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 4fb0675cca9..5cc5a001498 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12007,7 +12007,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_POLYMORPHIC: return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1); - case CPTK_IS_SAME_AS: + case CPTK_IS_SAME: return same_type_p (type1, type2); case CPTK_IS_STD_LAYOUT: @@ -12193,7 +12193,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_CLASS: case CPTK_IS_ENUM: case CPTK_IS_UNION: - case CPTK_IS_SAME_AS: + case CPTK_IS_SAME: break; case CPTK_IS_LAYOUT_COMPATIBLE:
On 10/3/22 08:48, Patrick Palka wrote: > On Fri, 30 Sep 2022, Jason Merrill wrote: > >> On 9/30/22 11:14, Patrick Palka wrote: >>> On Thu, 29 Sep 2022, Jason Merrill wrote: >>> >>>> On 9/29/22 11:05, Patrick Palka wrote: >>>>> Adding a new builtin trait currently involves some boilerplate (as can >>>>> be seen in r13-2956-g9ca147154074a0) of defining corresponding RID_ and >>>>> CPTK_ enumerators and adding them to various switch statements across >>>>> many files. The exact switch statements we need to change is determined >>>>> by whether the proposed trait yields a type or an expression. >>>>> >>>>> This RFC patch attempts to streamline this process via a centralized >>>>> cp-trait.def file for declaring the important parts about a builtin >>>>> trait >>>>> (whether it yields a type or an expression, its code, its spelling and >>>>> its arity) and using this file to automate away the switch statement >>>>> addition boilerplate. It also converts 9 traits to use this approach >>>>> by way of example (we can convert all the traits once the design is >>>>> settled). >>>>> >>>>> After this change, the process of adding a new builtin trait is just >>>>> (modulo tests): declare it in cp-trait.def, define its behavior in >>>>> finish_trait_type/expr, and handle it in diagnose_trait_expr if it's >>>>> an expression-yielding trait (this last step is unfortunate but since >>>>> the switch has no default case, we'll at least get a diagnostic if we >>>>> forget to do it). >>>>> >>>>> Does this look like a good approach? >>>> >>>> OK. >>> >>> Thanks a lot, I committed the following (which migrates all the >>> C++-specific traits to the new approach): >>> >>> -- >8 -- >>> >>> Subject: [PATCH] c++: streamline built-in trait addition process >>> >>> Adding a new built-in trait currently involves manual boilerplate >>> consisting of defining an rid enumerator for the identifier as well as a >>> corresponding cp_trait_kind enumerator and handling them in various switch >>> statements, the exact set of which depends on whether the proposed trait >>> yields (and thus is recognized as) a type or an expression. >>> >>> To streamline the process, this patch adds a central cp-trait.def file >>> that tabulates the essential details about each built-in trait (whether >>> it yields a type or an expression, its code, its spelling and its arity) >>> and uses this file to automate away the manual boilerplate. It also >>> migrates all the existing C++-specific built-in traits to use this >>> approach. >>> >>> After this change, adding a new built-in trait just entails declaring >>> it in cp-trait.def and defining its behavior in finish_trait_expr/type >>> (and handling it in diagnose_trait_expr, if it's an expression-yielding >>> trait). >>> >>> gcc/c-family/ChangeLog: >>> >>> * c-common.cc (c_common_reswords): Use cp/cp-trait.def to handle >>> C++ traits. >>> * c-common.h (enum rid): Likewise. >>> >>> gcc/cp/ChangeLog: >>> >>> * constraint.cc (diagnose_trait_expr): Likewise. >>> * cp-objcp-common.cc (names_builtin_p): Likewise. >>> * cp-tree.h (enum cp_trait_kind): Likewise. >>> * cxx-pretty-print.cc (pp_cxx_trait): Likewise. >>> * parser.cc (cp_keyword_starts_decl_specifier_p): Likewise. >>> (cp_parser_primary_expression): Likewise. >>> (cp_parser_trait): Likewise. >>> (cp_parser_simple_type_specifier): Likewise. >>> * cp-trait.def: New file. >>> --- >>> gcc/c-family/c-common.cc | 54 ++------- >>> gcc/c-family/c-common.h | 33 ++---- >>> gcc/cp/constraint.cc | 12 +- >>> gcc/cp/cp-objcp-common.cc | 44 +------- >>> gcc/cp/cp-trait.def | 106 ++++++++++++++++++ >>> gcc/cp/cp-tree.h | 46 +------- >>> gcc/cp/cxx-pretty-print.cc | 126 +-------------------- >>> gcc/cp/parser.cc | 217 ++++--------------------------------- >>> 8 files changed, 161 insertions(+), 477 deletions(-) >>> create mode 100644 gcc/cp/cp-trait.def >>> >>> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc >>> index 6e0af863a49..3c60a89bfe2 100644 >>> --- a/gcc/c-family/c-common.cc >>> +++ b/gcc/c-family/c-common.cc >>> @@ -378,7 +378,6 @@ const struct c_common_resword c_common_reswords[] = >>> { "__attribute", RID_ATTRIBUTE, 0 }, >>> { "__attribute__", RID_ATTRIBUTE, 0 }, >>> { "__auto_type", RID_AUTO_TYPE, D_CONLY }, >>> - { "__bases", RID_BASES, D_CXXONLY }, >>> { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY }, >>> { "__builtin_bit_cast", RID_BUILTIN_BIT_CAST, D_CXXONLY }, >>> { "__builtin_call_with_static_chain", >>> @@ -401,44 +400,12 @@ const struct c_common_resword c_common_reswords[] = >>> { "__const__", RID_CONST, 0 }, >>> { "__constinit", RID_CONSTINIT, D_CXXONLY }, >>> { "__decltype", RID_DECLTYPE, D_CXXONLY }, >>> - { "__direct_bases", RID_DIRECT_BASES, D_CXXONLY }, >>> { "__extension__", RID_EXTENSION, 0 }, >>> { "__func__", RID_C99_FUNCTION_NAME, 0 }, >>> - { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY }, >>> - { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY }, >>> - { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY }, >>> - { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, D_CXXONLY }, >>> - { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, >>> - { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, >>> - { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, >>> - { "__has_unique_object_representations", >>> RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, >>> - D_CXXONLY }, >>> - { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, >>> { "__imag", RID_IMAGPART, 0 }, >>> { "__imag__", RID_IMAGPART, 0 }, >>> { "__inline", RID_INLINE, 0 }, >>> { "__inline__", RID_INLINE, 0 }, >>> - { "__is_abstract", RID_IS_ABSTRACT, D_CXXONLY }, >>> - { "__is_aggregate", RID_IS_AGGREGATE, D_CXXONLY }, >>> - { "__is_base_of", RID_IS_BASE_OF, D_CXXONLY }, >>> - { "__is_class", RID_IS_CLASS, D_CXXONLY }, >>> - { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, >>> - { "__is_enum", RID_IS_ENUM, D_CXXONLY }, >>> - { "__is_final", RID_IS_FINAL, D_CXXONLY }, >>> - { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, >>> - { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, >>> - { "__is_pointer_interconvertible_base_of", >>> - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, >>> - { "__is_pod", RID_IS_POD, D_CXXONLY }, >>> - { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, >>> - { "__is_same", RID_IS_SAME_AS, D_CXXONLY }, >>> - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, >>> - { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, >>> - { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, >>> - { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY }, >>> - { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, >>> D_CXXONLY }, >>> - { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY }, >>> - { "__is_union", RID_IS_UNION, D_CXXONLY }, >>> { "__label__", RID_LABEL, 0 }, >>> { "__null", RID_NULL, 0 }, >>> { "__real", RID_REALPART, 0 }, >>> @@ -453,7 +420,6 @@ const struct c_common_resword c_common_reswords[] = >>> { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 }, >>> { "__typeof", RID_TYPEOF, 0 }, >>> { "__typeof__", RID_TYPEOF, 0 }, >>> - { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, >>> { "__volatile", RID_VOLATILE, 0 }, >>> { "__volatile__", RID_VOLATILE, 0 }, >>> { "__GIMPLE", RID_GIMPLE, D_CONLY }, >>> @@ -537,19 +503,13 @@ const struct c_common_resword c_common_reswords[] = >>> { "volatile", RID_VOLATILE, 0 }, >>> { "wchar_t", RID_WCHAR, D_CXXONLY }, >>> { "while", RID_WHILE, 0 }, >>> - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, >>> - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, >>> - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, >>> - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY >>> }, >>> - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, >>> - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, >>> - { "__reference_constructs_from_temporary", >>> RID_REF_CONSTRUCTS_FROM_TEMPORARY, >>> - D_CXXONLY }, >>> - { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, >>> - D_CXXONLY }, >>> - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, >>> - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, >>> - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, >>> + >>> +#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_AS, D_CXXONLY }, >>> /* C++ transactional memory. */ >>> { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, >>> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h >>> index d5c98d306ce..5f470d94f4a 100644 >>> --- a/gcc/c-family/c-common.h >>> +++ b/gcc/c-family/c-common.h >>> @@ -163,31 +163,14 @@ enum rid >>> RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, >>> /* C++ extensions */ >>> - RID_ADDRESSOF, RID_BASES, >>> - RID_BUILTIN_LAUNDER, RID_DIRECT_BASES, >>> - RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, >>> - RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, >>> - RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, >>> - RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS, >>> - RID_HAS_VIRTUAL_DESTRUCTOR, RID_BUILTIN_BIT_CAST, >>> - RID_IS_ABSTRACT, RID_IS_AGGREGATE, >>> - RID_IS_BASE_OF, RID_IS_CLASS, >>> - RID_IS_EMPTY, RID_IS_ENUM, >>> - RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, >>> - RID_IS_LITERAL_TYPE, >>> - RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, >>> - RID_IS_POD, RID_IS_POLYMORPHIC, >>> - RID_IS_SAME_AS, >>> - RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, >>> - RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, >>> - RID_IS_TRIVIALLY_COPYABLE, >>> - RID_IS_UNION, RID_UNDERLYING_TYPE, >>> - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, >>> - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, >>> - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, >>> - RID_REF_CONSTRUCTS_FROM_TEMPORARY, >>> - RID_REF_CONVERTS_FROM_TEMPORARY, >>> - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, >>> + RID_ADDRESSOF, >>> + 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/constraint.cc b/gcc/cp/constraint.cc >>> index ca73aff3f38..f4145571d92 100644 >>> --- a/gcc/cp/constraint.cc >>> +++ b/gcc/cp/constraint.cc >>> @@ -3711,13 +3711,11 @@ diagnose_trait_expr (tree expr, tree args) >>> inform (loc, " %qT is not a reference that binds to a temporary " >>> "object of type %qT (copy-initialization)", t1, t2); >>> break; >>> - case CPTK_BASES: >>> - case CPTK_DIRECT_BASES: >>> - case CPTK_UNDERLYING_TYPE: >>> - case CPTK_REMOVE_CV: >>> - case CPTK_REMOVE_REFERENCE: >>> - case CPTK_REMOVE_CVREF: >>> - /* We shouldn't see these non-expression traits. */ >>> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ >>> + case CPTK_##CODE: >>> +#include "cp-trait.def" >>> +#undef DEFTRAIT_TYPE >>> + /* Type-yielding traits aren't expressions. */ >>> gcc_unreachable (); >>> /* We deliberately omit the default case so that when adding a new >>> trait we'll get reminded (by way of a warning) to handle it here. >>> */ >>> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc >>> index 2d3f206b530..e4df30d9720 100644 >>> --- a/gcc/cp/cp-objcp-common.cc >>> +++ b/gcc/cp/cp-objcp-common.cc >>> @@ -430,46 +430,10 @@ names_builtin_p (const char *name) >>> case RID_BUILTIN_ASSOC_BARRIER: >>> case RID_BUILTIN_BIT_CAST: >>> case RID_OFFSETOF: >>> - case RID_HAS_NOTHROW_ASSIGN: >>> - case RID_HAS_NOTHROW_CONSTRUCTOR: >>> - case RID_HAS_NOTHROW_COPY: >>> - case RID_HAS_TRIVIAL_ASSIGN: >>> - case RID_HAS_TRIVIAL_CONSTRUCTOR: >>> - case RID_HAS_TRIVIAL_COPY: >>> - case RID_HAS_TRIVIAL_DESTRUCTOR: >>> - case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: >>> - case RID_HAS_VIRTUAL_DESTRUCTOR: >>> - case RID_IS_ABSTRACT: >>> - case RID_IS_AGGREGATE: >>> - case RID_IS_BASE_OF: >>> - case RID_IS_CLASS: >>> - case RID_IS_EMPTY: >>> - case RID_IS_ENUM: >>> - case RID_IS_FINAL: >>> - case RID_IS_LAYOUT_COMPATIBLE: >>> - case RID_IS_LITERAL_TYPE: >>> - case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: >>> - case RID_IS_POD: >>> - case RID_IS_POLYMORPHIC: >>> - case RID_IS_SAME_AS: >>> - case RID_IS_STD_LAYOUT: >>> - case RID_IS_TRIVIAL: >>> - case RID_IS_TRIVIALLY_ASSIGNABLE: >>> - case RID_IS_TRIVIALLY_CONSTRUCTIBLE: >>> - case RID_IS_TRIVIALLY_COPYABLE: >>> - case RID_IS_UNION: >>> - case RID_IS_ASSIGNABLE: >>> - case RID_IS_CONSTRUCTIBLE: >>> - case RID_IS_NOTHROW_ASSIGNABLE: >>> - case RID_IS_NOTHROW_CONSTRUCTIBLE: >>> - case RID_UNDERLYING_TYPE: >>> - case RID_IS_CONVERTIBLE: >>> - case RID_IS_NOTHROW_CONVERTIBLE: >>> - case RID_REF_CONSTRUCTS_FROM_TEMPORARY: >>> - case RID_REF_CONVERTS_FROM_TEMPORARY: >>> - case RID_REMOVE_CV: >>> - case RID_REMOVE_REFERENCE: >>> - case RID_REMOVE_CVREF: >>> +#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.def b/gcc/cp/cp-trait.def >>> new file mode 100644 >>> index 00000000000..922348a1659 >>> --- /dev/null >>> +++ b/gcc/cp/cp-trait.def >>> @@ -0,0 +1,106 @@ >>> +/* This file contains the definitions for C++-specific built-in traits. >>> + >>> + Copyright The GNU Toolchain Authors. >>> + >>> + 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/>. */ >>> + >>> +/* Add a DEFTRAIT_EXPR (CODE, NAME, N) line to this file to define an >>> + expression-yielding built-in trait that has internal code name CODE, is >>> + spelled as NAME and takes N type arguments (where N is either 1, 2, or >>> + the special value -1 which denotes that it takes at least one argument). >>> + Such traits are represented as TRAIT_EXPR tree whose TRAIT_EXPR_KIND is >>> + CPTK_CODE. Define the behavior of the trait in finish_trait_expr. */ >>> + >>> +/* Add a DEFTRAIT_TYPE (CODE, NAME, N) line to this file to define a >>> + type-yielding built-in trait as described above. Such traits are >>> + generally represented as a TRAIT_TYPE tree whose TRAIT_TYPE_KIND is >>> + CPTK_CODE (exceptions are BASES and DIRECT_BASES below). Define the >>> + behavior of the trait in finish_trait_type. */ >>> + >>> +#ifdef DEFTRAIT >>> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, >>> NAME, ARITY) >>> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, >>> ARITY) >>> +#define DEFTRAIT_EXPR_DEFAULTED >>> +#define DEFTRAIT_TYPE_DEFAULTED >>> +#endif >>> + >>> +#ifndef DEFTRAIT_EXPR >>> +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) >>> +#define DEFTRAIT_EXPR_DEFAULTED >>> +#endif >>> + >>> +#ifndef DEFTRAIT_TYPE >>> +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) >>> +#define DEFTRAIT_TYPE_DEFAULTED >>> +#endif >>> + >>> +DEFTRAIT_EXPR (HAS_NOTHROW_ASSIGN, "__has_nothrow_assign", 1) >>> +DEFTRAIT_EXPR (HAS_NOTHROW_CONSTRUCTOR, "__has_nothrow_constructor", 1) >>> +DEFTRAIT_EXPR (HAS_NOTHROW_COPY, "__has_nothrow_copy", 1) >>> +DEFTRAIT_EXPR (HAS_TRIVIAL_ASSIGN, "__has_trivial_assign", 1) >>> +DEFTRAIT_EXPR (HAS_TRIVIAL_CONSTRUCTOR, "__has_trivial_constructor", 1) >>> +DEFTRAIT_EXPR (HAS_TRIVIAL_COPY, "__has_trivial_copy", 1) >>> +DEFTRAIT_EXPR (HAS_TRIVIAL_DESTRUCTOR, "__has_trivial_destructor", 1) >>> +DEFTRAIT_EXPR (HAS_UNIQUE_OBJ_REPRESENTATIONS, >>> "__has_unique_object_representations", 1) >>> +DEFTRAIT_EXPR (HAS_VIRTUAL_DESTRUCTOR, "__has_virtual_destructor", 1) >>> +DEFTRAIT_EXPR (IS_ABSTRACT, "__is_abstract", 1) >>> +DEFTRAIT_EXPR (IS_AGGREGATE, "__is_aggregate", 1) >>> +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) >>> +DEFTRAIT_EXPR (IS_BASE_OF, "__is_base_of", 2) >>> +DEFTRAIT_EXPR (IS_CLASS, "__is_class", 1) >>> +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) >>> +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) >>> +DEFTRAIT_EXPR (IS_EMPTY, "__is_empty", 1) >>> +DEFTRAIT_EXPR (IS_ENUM, "__is_enum", 1) >>> +DEFTRAIT_EXPR (IS_FINAL, "__is_final", 1) >>> +DEFTRAIT_EXPR (IS_LAYOUT_COMPATIBLE, "__is_layout_compatible", 2) >>> +DEFTRAIT_EXPR (IS_LITERAL_TYPE, "__is_literal_type", 1) >>> +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) >>> +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) >>> +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) >>> +DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, >>> "__is_pointer_interconvertible_base_of", 2) >>> +DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) >>> +DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) >>> +DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) >> >> Can we make the code and name agree? I don't feel strongly about which way. > > I suppose we should keep __is_same as the canonical spelling (as per > PR92271), so changing the code name seems preferable. Like so? OK, thanks. > -- >8 -- > > Subject: [PATCH] c++: rename IS_SAME_AS trait code to IS_SAME > > ... to match the canonical spelling __is_same of the trait itself > (also spelled as __is_same_as). > > gcc/c-family/ChangeLog: > > * c-common.cc (c_common_reswords): Use RID_IS_SAME instead of > RID_IS_SAME_AS. > > gcc/cp/ChangeLog: > > * constraint.cc (diagnose_trait_expr): Use CPTK_IS_SAME instead > of CPTK_IS_SAME_AS. > * cp-trait.def (IS_SAME_AS): Rename to ... > (IS_SAME): ... this. > * pt.cc (alias_ctad_tweaks): Use CPTK_IS_SAME instead of > CPTK_IS_SAME_AS. > * semantics.cc (trait_expr_value): Likewise. > (finish_trait_expr): Likewise. > --- > gcc/c-family/c-common.cc | 2 +- > gcc/cp/constraint.cc | 2 +- > gcc/cp/cp-trait.def | 2 +- > gcc/cp/pt.cc | 2 +- > gcc/cp/semantics.cc | 4 ++-- > 5 files changed, 6 insertions(+), 6 deletions(-) > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > index 3c60a89bfe2..4f9878d2695 100644 > --- a/gcc/c-family/c-common.cc > +++ b/gcc/c-family/c-common.cc > @@ -509,7 +509,7 @@ const struct c_common_resword c_common_reswords[] = > #include "cp/cp-trait.def" > #undef DEFTRAIT > /* An alias for __is_same. */ > - { "__is_same_as", RID_IS_SAME_AS, D_CXXONLY }, > + { "__is_same_as", RID_IS_SAME, D_CXXONLY }, > > /* C++ transactional memory. */ > { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc > index f4145571d92..74898ca1a23 100644 > --- a/gcc/cp/constraint.cc > +++ b/gcc/cp/constraint.cc > @@ -3649,7 +3649,7 @@ diagnose_trait_expr (tree expr, tree args) > case CPTK_IS_POLYMORPHIC: > inform (loc, " %qT is not a polymorphic type", t1); > break; > - case CPTK_IS_SAME_AS: > + case CPTK_IS_SAME: > inform (loc, " %qT is not the same as %qT", t1, t2); > break; > case CPTK_IS_STD_LAYOUT: > diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def > index 922348a1659..823899a26c5 100644 > --- a/gcc/cp/cp-trait.def > +++ b/gcc/cp/cp-trait.def > @@ -75,7 +75,7 @@ DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) > DEFTRAIT_EXPR (IS_POINTER_INTERCONVERTIBLE_BASE_OF, "__is_pointer_interconvertible_base_of", 2) > DEFTRAIT_EXPR (IS_POD, "__is_pod", 1) > DEFTRAIT_EXPR (IS_POLYMORPHIC, "__is_polymorphic", 1) > -DEFTRAIT_EXPR (IS_SAME_AS, "__is_same", 2) > +DEFTRAIT_EXPR (IS_SAME, "__is_same", 2) > DEFTRAIT_EXPR (IS_STD_LAYOUT, "__is_standard_layout", 1) > DEFTRAIT_EXPR (IS_TRIVIAL, "__is_trivial", 1) > DEFTRAIT_EXPR (IS_TRIVIALLY_ASSIGNABLE, "__is_trivially_assignable", 2) > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc > index 258f76d6e47..bce2a777922 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -30029,7 +30029,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) > /* FIXME this should mean they don't compare as equivalent. */ > || dependent_alias_template_spec_p (atype, nt_opaque)) > { > - tree same = finish_trait_expr (loc, CPTK_IS_SAME_AS, atype, ret); > + tree same = finish_trait_expr (loc, CPTK_IS_SAME, atype, ret); > ci = append_constraint (ci, same); > } > > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc > index 4fb0675cca9..5cc5a001498 100644 > --- a/gcc/cp/semantics.cc > +++ b/gcc/cp/semantics.cc > @@ -12007,7 +12007,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) > case CPTK_IS_POLYMORPHIC: > return CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1); > > - case CPTK_IS_SAME_AS: > + case CPTK_IS_SAME: > return same_type_p (type1, type2); > > case CPTK_IS_STD_LAYOUT: > @@ -12193,7 +12193,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) > case CPTK_IS_CLASS: > case CPTK_IS_ENUM: > case CPTK_IS_UNION: > - case CPTK_IS_SAME_AS: > + case CPTK_IS_SAME: > break; > > case CPTK_IS_LAYOUT_COMPATIBLE:
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 6e0af863a49..1b2fd37c583 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -537,19 +537,14 @@ const struct c_common_resword c_common_reswords[] = { "volatile", RID_VOLATILE, 0 }, { "wchar_t", RID_WCHAR, D_CXXONLY }, { "while", RID_WHILE, 0 }, - { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY }, - { "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY }, - { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY }, - { "__is_convertible", RID_IS_CONVERTIBLE, D_CXXONLY }, - { "__is_nothrow_convertible", RID_IS_NOTHROW_CONVERTIBLE, D_CXXONLY }, { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY, D_CXXONLY }, { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY, D_CXXONLY }, - { "__remove_cv", RID_REMOVE_CV, D_CXXONLY }, - { "__remove_reference", RID_REMOVE_REFERENCE, D_CXXONLY }, - { "__remove_cvref", RID_REMOVE_CVREF, D_CXXONLY }, +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + { NAME, RID_##CODE, D_CXXONLY }, +#include "cp/cp-trait.def" +#undef DEFTRAIT /* C++ transactional memory. */ { "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5c98d306ce..b306815c23b 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -182,12 +182,12 @@ enum rid RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, RID_IS_TRIVIALLY_COPYABLE, RID_IS_UNION, RID_UNDERLYING_TYPE, - RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE, - RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE, - RID_IS_CONVERTIBLE, RID_IS_NOTHROW_CONVERTIBLE, RID_REF_CONSTRUCTS_FROM_TEMPORARY, RID_REF_CONVERTS_FROM_TEMPORARY, - RID_REMOVE_CV, RID_REMOVE_REFERENCE, RID_REMOVE_CVREF, +#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/constraint.cc b/gcc/cp/constraint.cc index ca73aff3f38..9323bb091e1 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3714,9 +3714,10 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_BASES: case CPTK_DIRECT_BASES: case CPTK_UNDERLYING_TYPE: - case CPTK_REMOVE_CV: - case CPTK_REMOVE_REFERENCE: - case CPTK_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case CPTK_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE /* We shouldn't see these non-expression traits. */ gcc_unreachable (); /* We deliberately omit the default case so that when adding a new diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 2d3f206b530..bc397a5447f 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -458,18 +458,13 @@ names_builtin_p (const char *name) case RID_IS_TRIVIALLY_CONSTRUCTIBLE: case RID_IS_TRIVIALLY_COPYABLE: case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: case RID_UNDERLYING_TYPE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: case RID_REF_CONSTRUCTS_FROM_TEMPORARY: case RID_REF_CONVERTS_FROM_TEMPORARY: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT return true; default: break; diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def new file mode 100644 index 00000000000..817951f3e42 --- /dev/null +++ b/gcc/cp/cp-trait.def @@ -0,0 +1,37 @@ +#ifdef DEFTRAIT +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) DEFTRAIT(tcc_expression, CODE, NAME, ARITY) +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) DEFTRAIT(tcc_type, CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#define DEFTRAIT_TYPE_DEFAULTED +#endif + +#ifndef DEFTRAIT_EXPR +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) +#define DEFTRAIT_EXPR_DEFAULTED +#endif + +#ifndef DEFTRAIT_TYPE +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) +#define DEFTRAIT_TYPE_DEFAULTED +#endif + +DEFTRAIT_EXPR (IS_ASSIGNABLE, "__is_assignable", 2) +DEFTRAIT_EXPR (IS_NOTHROW_ASSIGNABLE, "__is_nothrow_assignable", 2) +DEFTRAIT_EXPR (IS_CONSTRUCTIBLE, "__is_constructible", -1) +DEFTRAIT_EXPR (IS_NOTHROW_CONSTRUCTIBLE, "__is_nothrow_constructible", -1) +DEFTRAIT_EXPR (IS_CONVERTIBLE, "__is_convertible", 2) +DEFTRAIT_EXPR (IS_NOTHROW_CONVERTIBLE, "__is_nothrow_convertible", 2) + +DEFTRAIT_TYPE (REMOVE_CV, "__remove_cv", 1) +DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1) +DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1) + +#ifdef DEFTRAIT_EXPR_DEFAULTED +#undef DEFTRAIT_EXPR +#undef DEFTRAIT_EXPR_DEFAULTED +#endif + +#ifdef DEFTRAIT_TYPE_DEFAULTED +#undef DEFTRAIT_TYPE +#undef DEFTRAIT_TYPE_DEFAULTED +#endif diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3cbcdf726ca..8c5a85ab5fe 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1405,17 +1405,12 @@ enum cp_trait_kind CPTK_IS_TRIVIALLY_COPYABLE, CPTK_IS_UNION, CPTK_UNDERLYING_TYPE, - CPTK_IS_ASSIGNABLE, - CPTK_IS_CONSTRUCTIBLE, - CPTK_IS_NOTHROW_ASSIGNABLE, - CPTK_IS_NOTHROW_CONSTRUCTIBLE, - CPTK_IS_CONVERTIBLE, - CPTK_IS_NOTHROW_CONVERTIBLE, CPTK_REF_CONSTRUCTS_FROM_TEMPORARY, CPTK_REF_CONVERTS_FROM_TEMPORARY, - CPTK_REMOVE_CV, - CPTK_REMOVE_REFERENCE, - CPTK_REMOVE_CVREF, +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + CPTK_##CODE, +#include "cp/cp-trait.def" +#undef DEFTRAIT }; /* The types that we are processing. */ diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index b91615439e4..a2ddbcb899a 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -2701,24 +2701,6 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) case CPTK_IS_LITERAL_TYPE: pp_cxx_ws_string (pp, "__is_literal_type"); break; - case CPTK_IS_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_assignable"); - break; - case CPTK_IS_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_constructible"); - break; - case CPTK_IS_NOTHROW_ASSIGNABLE: - pp_cxx_ws_string (pp, "__is_nothrow_assignable"); - break; - case CPTK_IS_NOTHROW_CONSTRUCTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_constructible"); - break; - case CPTK_IS_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_convertible"); - break; - case CPTK_IS_NOTHROW_CONVERTIBLE: - pp_cxx_ws_string (pp, "__is_nothrow_convertible"); - break; case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY: pp_cxx_ws_string (pp, "__reference_constructs_from_temporary"); break; @@ -2728,15 +2710,12 @@ pp_cxx_trait (cxx_pretty_printer *pp, tree t) case CPTK_UNDERLYING_TYPE: pp_cxx_ws_string (pp, "__underlying_type"); break; - case CPTK_REMOVE_CV: - pp_cxx_ws_string (pp, "__remove_cv"); - break; - case CPTK_REMOVE_REFERENCE: - pp_cxx_ws_string (pp, "__remove_reference"); - break; - case CPTK_REMOVE_CVREF: - pp_cxx_ws_string (pp, "__remove_cvref"); +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case CPTK_##CODE: \ + pp_cxx_ws_string (pp, NAME); \ break; +#include "cp/cp-trait.def" +#undef DEFTRAIT default: gcc_unreachable (); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index d592d783250..138892716b4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -1147,9 +1147,10 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword) /* C++11 extensions. */ case RID_DECLTYPE: case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE case RID_CONSTEXPR: /* C++20 extensions. */ case RID_CONSTINIT: @@ -5923,14 +5924,12 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_TRIVIALLY_CONSTRUCTIBLE: case RID_IS_TRIVIALLY_COPYABLE: case RID_IS_UNION: - case RID_IS_ASSIGNABLE: - case RID_IS_CONSTRUCTIBLE: - case RID_IS_NOTHROW_ASSIGNABLE: - case RID_IS_NOTHROW_CONSTRUCTIBLE: - case RID_IS_CONVERTIBLE: - case RID_IS_NOTHROW_CONVERTIBLE: case RID_REF_CONSTRUCTS_FROM_TEMPORARY: case RID_REF_CONVERTS_FROM_TEMPORARY: +#define DEFTRAIT_EXPR(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_EXPR return cp_parser_trait (parser, token->keyword); // C++ concepts @@ -10998,30 +10997,6 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) case RID_DIRECT_BASES: kind = CPTK_DIRECT_BASES; break; - case RID_IS_ASSIGNABLE: - kind = CPTK_IS_ASSIGNABLE; - binary = true; - break; - case RID_IS_CONSTRUCTIBLE: - kind = CPTK_IS_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_NOTHROW_ASSIGNABLE: - kind = CPTK_IS_NOTHROW_ASSIGNABLE; - binary = true; - break; - case RID_IS_NOTHROW_CONSTRUCTIBLE: - kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE; - variadic = true; - break; - case RID_IS_CONVERTIBLE: - kind = CPTK_IS_CONVERTIBLE; - binary = true; - break; - case RID_IS_NOTHROW_CONVERTIBLE: - kind = CPTK_IS_NOTHROW_CONVERTIBLE; - binary = true; - break; case RID_REF_CONSTRUCTS_FROM_TEMPORARY: kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY; binary = true; @@ -11030,18 +11005,15 @@ cp_parser_trait (cp_parser* parser, enum rid keyword) kind = CPTK_REF_CONVERTS_FROM_TEMPORARY; binary = true; break; - case RID_REMOVE_CV: - kind = CPTK_REMOVE_CV; - type = true; - break; - case RID_REMOVE_REFERENCE: - kind = CPTK_REMOVE_REFERENCE; - type = true; - break; - case RID_REMOVE_CVREF: - kind = CPTK_REMOVE_CVREF; - type = true; +#define DEFTRAIT(TCC, CODE, NAME, ARITY) \ + case RID_##CODE: \ + type = (TCC == tcc_type); \ + kind = CPTK_##CODE; \ + binary = (ARITY == 2); \ + variadic = (ARITY == -1); \ break; +#include "cp/cp-trait.def" +#undef DEFTRAIT default: gcc_unreachable (); } @@ -19882,9 +19854,10 @@ cp_parser_simple_type_specifier (cp_parser* parser, return type; case RID_UNDERLYING_TYPE: - case RID_REMOVE_CV: - case RID_REMOVE_REFERENCE: - case RID_REMOVE_CVREF: +#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \ + case RID_##CODE: +#include "cp/cp-trait.def" +#undef DEFTRAIT_TYPE type = cp_parser_trait (parser, token->keyword); if (decl_specs) cp_parser_set_decl_spec_type (decl_specs, type,