From: Jason Merrill <jason@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
Date: Wed, 28 Sep 2022 14:49:35 -0400 [thread overview]
Message-ID: <4276ddd3-63e9-adc1-e448-09bfb5d7056a@redhat.com> (raw)
In-Reply-To: <b75637a5-6c6d-af86-8ca6-e45d35df2373@idea>
On 9/28/22 12:36, Patrick Palka wrote:
> On Tue, 27 Sep 2022, Jason Merrill wrote:
>
>> On 9/27/22 15:50, Patrick Palka wrote:
>>> We already have generic support for predicate-like traits that yield a
>>> boolean via TRAIT_EXPR, but we lack the same support for transform-like
>>> traits that yield a type. Such support would be useful for implementing
>>> efficient built-ins for std::decay and std::remove_cvref and other
>>> conceptually simple type traits that are otherwise relatively expensive
>>> to implement.
>>>
>>> This patch implements a generic TRAIT_TYPE type and replaces the
>>> existing hardcoded UNDERLYING_TYPE type to use TRAIT_TYPE instead.
>>
>> Sounds good, perhaps we also want to convert BASES to e.g. TRAIT_TYPE_PACK at
>> some point...
>
> *nod*
>
>>
>>> gcc/cp/ChangeLog:
>>>
>>> * cp-objcp-common.cc (cp_common_init_ts): Replace
>>> UNDERLYING_TYPE with TRAIT_TYPE.
>>> * cp-tree.def (TRAIT_TYPE): Define.
>>> (UNDERLYING_TYPE): Remove.
>>> * cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
>>> (TRAIT_TYPE_KIND): Define.
>>> (TRAIT_TYPE_TYPE1): Define.
>>> (TRAIT_TYPE_TYPE2): Define.
>>> (WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
>>> (finish_trait_type): Declare.
>>> * cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
>>> Adjust after renaming pp_cxx_trait_expression.
>>> (cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
>>> TRAIT_TYPE.
>>> (pp_cxx_trait_expression): Rename to ...
>>> (pp_cxx_trait): ... this. Handle TRAIT_TYPE as well. Correct
>>> pretty printing of the trailing arguments.
>>> * cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
>>> (pp_cxx_trait_type): ... this.
>>> * error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
>>> <case TRAIT_TYPE>: New.
>>> (dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
>>> (dump_type_suffix): Likewise.
>>> * mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
>>> <case TRAIT_TYPE>: New.
>>> * module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
>>> Remove.
>>> <case TRAIT_TYPE>: New.
>>> (trees_in::tree_node): Likewise.
>>> * parser.cc (cp_parser_primary_expression): Adjust after
>>> renaming cp_parser_trait_expr.
>>> (cp_parser_trait_expr): Rename to ...
>>> (cp_parser_trait): ... this. Call finish_trait_type for traits
>>> that yield a type.
>>> (cp_parser_simple_type_specifier): Adjust after renaming
>>> cp_parser_trait_expr.
>>> * pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
>>> Remove.
>>> <case TRAIT_TYPE>: New.
>>> (tsubst): Likewise.
>>> (unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
>>> (dependent_type_p_r): Likewise.
>>> * semantics.cc (finish_underlying_type): Don't return
>>> UNDERLYING_TYPE anymore when processing_template_decl.
>>> (finish_trait_type): Define.
>>> * tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
>>> <case TRAIT_TYPE>: New.
>>> (cp_walk_subtrees): Likewise.
>>> * typeck.cc (structural_comptypes): Likewise.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * g++.dg/ext/underlying_type7.C: Adjust expected error message.
>>> ---
>>> gcc/cp/cp-objcp-common.cc | 2 +-
>>> gcc/cp/cp-tree.def | 9 ++--
>>> gcc/cp/cp-tree.h | 18 ++++++++
>>> gcc/cp/cxx-pretty-print.cc | 49 ++++++++++++++-------
>>> gcc/cp/cxx-pretty-print.h | 2 +-
>>> gcc/cp/error.cc | 14 +++---
>>> gcc/cp/mangle.cc | 5 ++-
>>> gcc/cp/module.cc | 24 +++++++++-
>>> gcc/cp/parser.cc | 24 +++++-----
>>> gcc/cp/pt.cc | 26 +++++++----
>>> gcc/cp/semantics.cc | 41 ++++++++++++-----
>>> gcc/cp/tree.cc | 22 ++++++---
>>> gcc/cp/typeck.cc | 7 ++-
>>> gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C | 4 +-
>>> gcc/testsuite/g++.dg/ext/underlying_type7.C | 2 +-
>>> 15 files changed, 171 insertions(+), 78 deletions(-)
>>>
>>> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
>>> index 64975699351..380f288a7f1 100644
>>> --- a/gcc/cp/cp-objcp-common.cc
>>> +++ b/gcc/cp/cp-objcp-common.cc
>>> @@ -518,7 +518,7 @@ cp_common_init_ts (void)
>>> MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
>>> MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
>>> MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
>>> - MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
>>> + MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
>>> MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
>>> MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
>>> MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
>>> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
>>> index f9cbd339f19..f83b4c54d43 100644
>>> --- a/gcc/cp/cp-tree.def
>>> +++ b/gcc/cp/cp-tree.def
>>> @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr",
>>> tcc_expression, 1)
>>> /** C++ extensions. */
>>> -/* Represents a trait expression during template expansion. */
>>> +/* Represents a templated trait that yields an expression. */
>>> DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
>>> +/* Represents a templated trait that yields a type. */
>>> +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
>>> +
>>> /* A lambda expression. This is a C++0x extension.
>>> LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may
>>> be
>>> none.
>>> @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr",
>>> tcc_exceptional, 0)
>>> DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction.
>>> */
>>> DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
>>> -/* A type designated by `__underlying_type (type)'.
>>> - UNDERLYING_TYPE_TYPE is the type in question. */
>>> -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
>>> -
>>> /* A type designated by one of the bases type traits.
>>> BASES_TYPE is the type in question. */
>>> DEFTREECODE (BASES, "bases", tcc_type, 0)
>>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>>> index 99b486b8002..c9adf1b3822 100644
>>> --- a/gcc/cp/cp-tree.h
>>> +++ b/gcc/cp/cp-tree.h
>>> @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
>>> enum cp_trait_kind kind;
>>> };
>>> +/* An INTEGER_CST containing the kind of the trait type NODE. */
>>> +#define TRAIT_TYPE_KIND_RAW(NODE) \
>>> + TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
>>> +
>>> +/* The kind of the trait type NODE. */
>>> +#define TRAIT_TYPE_KIND(NODE) \
>>> + ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
>>> +
>>> +/* The first argument of the trait type NODE. */
>>> +#define TRAIT_TYPE_TYPE1(NODE) \
>>> + TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
>>> +
>>> +/* The rest of the arguments of the trait type NODE. */
>>> +#define TRAIT_TYPE_TYPE2(NODE) \
>>> + TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
>>
>> Can we also store the location of the trait use?
>
> Hmm, I suppose we could create a TYPE_DECL for each use and store it
> there, but I'm not really sure how we'd use this location? Presumably
> for diagnostics, but I can't come up with an example.
>
> FWIW I think currently TYPENAME_TYPE is the only "non-declared" type that
> has a TYPE_DECL (and location info). DECLTYPE_TYPE, TYPE_PACK_EXPANSION,
> etc don't have TYPE_DECL (or location info). I wonder why only
> TYPENAME_TYPE has one?
Pretty sure TYPENAME_TYPE was the first one added, I guess the later
ones just didn't bother because as you mention, it wouldn't actually be
used: looks like all the occurrences of "location_of (type)" are dealing
with class declarations.
>>> +
>>> /* Identifiers used for lambda types are almost anonymous. Use this
>>> spare flag to distinguish them (they also have the anonymous flag). */
>>> #define IDENTIFIER_LAMBDA_P(NODE) \
>>> @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
>>> || TREE_CODE (T) == TYPEOF_TYPE \
>>> || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \
>>> || TREE_CODE (T) == DECLTYPE_TYPE \
>>> + || TREE_CODE (T) == TRAIT_TYPE \
>>> || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
>>> /* Nonzero if T is a class (or struct or union) type. Also nonzero
>>> @@ -7730,6 +7747,7 @@ extern tree finish_decltype_type (tree,
>>> bool, tsubst_flags_t);
>>> extern tree fold_builtin_is_corresponding_member (location_t, int, tree
>>> *);
>>> extern tree fold_builtin_is_pointer_inverconvertible_with_class
>>> (location_t, int, tree *);
>>> extern tree finish_trait_expr (location_t, enum
>>> cp_trait_kind, tree, tree);
>>> +extern tree finish_trait_type (enum cp_trait_kind,
>>> tree, tree);
>>> extern tree build_lambda_expr (void);
>>> extern tree build_lambda_object (tree);
>>> extern tree begin_lambda_type (tree);
>>> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
>>> index e18143e39a9..d484019a539 100644
>>> --- a/gcc/cp/cxx-pretty-print.cc
>>> +++ b/gcc/cp/cxx-pretty-print.cc
>>> @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
>>> break;
>>> case TRAIT_EXPR:
>>> - pp_cxx_trait_expression (this, t);
>>> + pp_cxx_trait (this, t);
>>> break;
>>> case VA_ARG_EXPR:
>>> @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
>>> break;
>>> case TRAIT_EXPR:
>>> - pp_cxx_trait_expression (this, t);
>>> + pp_cxx_trait (this, t);
>>> break;
>>> case ATOMIC_CONSTR:
>>> @@ -1876,7 +1876,7 @@ cxx_pretty_printer::type_id (tree t)
>>> case TEMPLATE_PARM_INDEX:
>>> case TEMPLATE_DECL:
>>> case TYPEOF_TYPE:
>>> - case UNDERLYING_TYPE:
>>> + case TRAIT_TYPE:
>>
>> Does this ever end up calling pp_cxx_trait? Is this code even reachable? It
>> looks like we were already missing support for UNDERLYING_TYPE in
>> cxx_pretty_printer::simple_type_specifier.
>
> Looks like it's reachable at least through pp_cxx_trait (which calls
> type_id on each of the trait's arguments), so e.g. when pretty printing
> __remove_cv(__remove_cv(T)) we currently get the "unhandled tree code"
> fallback for the inner trait. I fixed this in v2 below by adding support
> for UNDERLYING_TYPE in simple_type_specifier and added a testcase.
>
>>
>>> case DECLTYPE_TYPE:
>>> case NULLPTR_TYPE:
>>> case TEMPLATE_ID_EXPR:
>>> @@ -2594,9 +2594,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer
>>> *pp, tree t)
>>> }
>>> void
>>> -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
>>> +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
>>> {
>>> - cp_trait_kind kind = TRAIT_EXPR_KIND (t);
>>> + cp_trait_kind kind;
>>> + tree type1, type2;
>>> + if (TREE_CODE (t) == TRAIT_EXPR)
>>> + {
>>> + kind = TRAIT_EXPR_KIND (t);
>>> + type1 = TRAIT_EXPR_TYPE1 (t);
>>> + type2 = TRAIT_EXPR_TYPE2 (t);
>>> + }
>>> + else
>>> + {
>>> + kind = TRAIT_TYPE_KIND (t);
>>> + type1 = TRAIT_TYPE_TYPE1 (t);
>>> + type2 = TRAIT_TYPE_TYPE2 (t);
>>> + }
>>> switch (kind)
>>> {
>>> @@ -2708,23 +2721,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp,
>>> tree t)
>>> 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;
>>> default:
>>> gcc_unreachable ();
>>> }
>>> pp_cxx_left_paren (pp);
>>> - pp->type_id (TRAIT_EXPR_TYPE1 (t));
>>> -
>>> - if (kind == CPTK_IS_BASE_OF
>>> - || kind == CPTK_IS_SAME_AS
>>> - || kind == CPTK_IS_LAYOUT_COMPATIBLE
>>> - || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
>>> + pp->type_id (type1);
>>> + if (type2)
>>> {
>>> - pp_cxx_separate_with (pp, ',');
>>> - pp->type_id (TRAIT_EXPR_TYPE2 (t));
>>> + if (TREE_CODE (type2) != TREE_LIST)
>>> + {
>>> + pp_cxx_separate_with (pp, ',');
>>> + pp->type_id (type2);
>>> + }
>>> + else
>>> + for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
>>> + {
>>> + pp_cxx_separate_with (pp, ',');
>>> + pp->type_id (TREE_VALUE (arg));
>>> + }
>>> }
>>> -
>>> pp_cxx_right_paren (pp);
>>> }
>>> diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
>>> index 593bd91d4f7..25a2c7c8d4a 100644
>>> --- a/gcc/cp/cxx-pretty-print.h
>>> +++ b/gcc/cp/cxx-pretty-print.h
>>> @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
>>> void pp_cxx_separate_with (cxx_pretty_printer *, int);
>>> void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
>>> -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
>>> +void pp_cxx_trait (cxx_pretty_printer *, tree);
>>> void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
>>> void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
>>> void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
>>> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
>>> index 0389f35d731..4bf9a83f20b 100644
>>> --- a/gcc/cp/error.cc
>>> +++ b/gcc/cp/error.cc
>>> @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
>>> pp_cxx_right_paren (pp);
>>> break;
>>> - case UNDERLYING_TYPE:
>>> - pp_cxx_ws_string (pp, "__underlying_type");
>>> - pp_cxx_whitespace (pp);
>>> - pp_cxx_left_paren (pp);
>>> - dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags &
>>> ~TFF_EXPR_IN_PARENS);
>>> - pp_cxx_right_paren (pp);
>>> + case TRAIT_TYPE:
>>> + pp_cxx_trait (pp, t);
>>> break;
>>> case TYPE_PACK_EXPANSION:
>>> @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int
>>> flags)
>>> case COMPLEX_TYPE:
>>> case VECTOR_TYPE:
>>> case TYPEOF_TYPE:
>>> - case UNDERLYING_TYPE:
>>> + case TRAIT_TYPE:
>>> case DECLTYPE_TYPE:
>>> case TYPE_PACK_EXPANSION:
>>> case FIXED_POINT_TYPE:
>>> @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int
>>> flags)
>>> case COMPLEX_TYPE:
>>> case VECTOR_TYPE:
>>> case TYPEOF_TYPE:
>>> - case UNDERLYING_TYPE:
>>> + case TRAIT_TYPE:
>>> case DECLTYPE_TYPE:
>>> case TYPE_PACK_EXPANSION:
>>> case FIXED_POINT_TYPE:
>>> @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
>>> break;
>>> case TRAIT_EXPR:
>>> - pp_cxx_trait_expression (pp, t);
>>> + pp_cxx_trait (pp, t);
>>> break;
>>> case VA_ARG_EXPR:
>>> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
>>> index 00d283fff8c..fc750fc5d8e 100644
>>> --- a/gcc/cp/mangle.cc
>>> +++ b/gcc/cp/mangle.cc
>>> @@ -2389,8 +2389,9 @@ write_type (tree type)
>>> sorry ("mangling %<typeof%>, use %<decltype%> instead");
>>> break;
>>> - case UNDERLYING_TYPE:
>>> - sorry ("mangling %<__underlying_type%>");
>>> + case TRAIT_TYPE:
>>> + error ("use of built-in trait %qT in function signature; "
>>> + "use library traits instead", type);
>>> break;
>>> case LANG_TYPE:
>>> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
>>> index 7496df5e843..25741e5d827 100644
>>> --- a/gcc/cp/module.cc
>>> +++ b/gcc/cp/module.cc
>>> @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
>>> case DECLTYPE_TYPE:
>>> case TYPEOF_TYPE:
>>> - case UNDERLYING_TYPE:
>>> case DEPENDENT_OPERATOR_TYPE:
>>> tree_node (TYPE_VALUES_RAW (type));
>>> if (TREE_CODE (type) == DECLTYPE_TYPE)
>>> @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
>>> tree_node_bools (type);
>>> break;
>>> + case TRAIT_TYPE:
>>> + tree_node (TRAIT_TYPE_KIND_RAW (type));
>>> + tree_node (TRAIT_TYPE_TYPE1 (type));
>>> + tree_node (TRAIT_TYPE_TYPE2 (type));
>>> + break;
>>> +
>>> case TYPE_ARGUMENT_PACK:
>>> /* No additional data. */
>>> break;
>>> @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
>>> case DECLTYPE_TYPE:
>>> case TYPEOF_TYPE:
>>> - case UNDERLYING_TYPE:
>>> case DEPENDENT_OPERATOR_TYPE:
>>> {
>>> tree expr = tree_node ();
>>> @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
>>> }
>>> break;
>>> + case TRAIT_TYPE:
>>> + {
>>> + tree kind = tree_node ();
>>> + tree type1 = tree_node ();
>>> + tree type2 = tree_node ();
>>> + if (!get_overrun ())
>>> + {
>>> + res = cxx_make_type (TRAIT_TYPE);
>>> + TRAIT_TYPE_KIND_RAW (res) = kind;
>>> + TRAIT_TYPE_TYPE1 (res) = type1;
>>> + TRAIT_TYPE_TYPE2 (res) = type2;
>>> + SET_TYPE_STRUCTURAL_EQUALITY (res);
>>
>> This needs a rationale for structural equality rather than canonicalization.
>
> Fixed in v2. I suppose we can get away with structural equality given
> the intended use of these traits is to implement the standard library
> traits.
>
> Also in v2, make sure to propagate the cv-quals of TRAIT_TYPE during
> substitution.
OK.
> -- >8 --
>
> Subject: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR
>
> gcc/cp/ChangeLog:
>
> * cp-objcp-common.cc (cp_common_init_ts): Replace
> UNDERLYING_TYPE with TRAIT_TYPE.
> * cp-tree.def (TRAIT_TYPE): Define.
> (UNDERLYING_TYPE): Remove.
> * cp-tree.h (TRAIT_TYPE_KIND_RAW): Define.
> (TRAIT_TYPE_KIND): Define.
> (TRAIT_TYPE_TYPE1): Define.
> (TRAIT_TYPE_TYPE2): Define.
> (WILDCARD_TYPE_P): Return true for TRAIT_TYPE.
> (finish_trait_type): Declare.
> * cxx-pretty-print.cc (cxx_pretty_printer::primary_expression):
> Adjust after renaming pp_cxx_trait_expression.
> (cxx_pretty_printer::simple_type_specifier) <case TRAIT_TYPE>:
> New.
> (cxx_pretty_printer::type_id): Replace UNDERLYING_TYPE with
> TRAIT_TYPE.
> (pp_cxx_trait_expression): Rename to ...
> (pp_cxx_trait): ... this. Handle TRAIT_TYPE as well. Correct
> pretty printing of the trailing arguments.
> * cxx-pretty-print.h (pp_cxx_trait_expression): Rename to ...
> (pp_cxx_trait_type): ... this.
> * error.cc (dump_type) <case UNDERLYING_TYPE>: Remove.
> <case TRAIT_TYPE>: New.
> (dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE.
> (dump_type_suffix): Likewise.
> * mangle.cc (write_type) <case UNDERLYING_TYPE>: Remove.
> <case TRAIT_TYPE>: New.
> * module.cc (trees_out::type_node) <case UNDERLYING_TYPE>:
> Remove.
> <case TRAIT_TYPE>: New.
> (trees_in::tree_node): Likewise.
> * parser.cc (cp_parser_primary_expression): Adjust after
> renaming cp_parser_trait_expr.
> (cp_parser_trait_expr): Rename to ...
> (cp_parser_trait): ... this. Call finish_trait_type for traits
> that yield a type.
> (cp_parser_simple_type_specifier): Adjust after renaming
> cp_parser_trait_expr.
> * pt.cc (for_each_template_parm_r) <case UNDERLYING_TYPE>:
> Remove.
> <case TRAIT_TYPE>: New.
> (tsubst): Likewise.
> (unify): Replace UNDERLYING_TYPE with TRAIT_TYPE.
> (dependent_type_p_r): Likewise.
> * semantics.cc (finish_underlying_type): Don't return
> UNDERLYING_TYPE anymore when processing_template_decl.
> (finish_trait_type): Define.
> * tree.cc (strip_typedefs) <case UNDERLYING_TYPE>: Remove.
> <case TRAIT_TYPE>: New.
> (cp_walk_subtrees): Likewise.
> * typeck.cc (structural_comptypes): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/ext/underlying_type7.C: Adjust expected error message.
> * g++.dg/ext/underlying_type13.C: New test.
> * g++.dg/ext/underlying_type14.C: New test.
> ---
> gcc/cp/cp-objcp-common.cc | 2 +-
> gcc/cp/cp-tree.def | 9 ++--
> gcc/cp/cp-tree.h | 18 +++++++
> gcc/cp/cxx-pretty-print.cc | 53 ++++++++++++++------
> gcc/cp/cxx-pretty-print.h | 2 +-
> gcc/cp/error.cc | 14 ++----
> gcc/cp/mangle.cc | 5 +-
> gcc/cp/module.cc | 24 ++++++++-
> gcc/cp/parser.cc | 24 ++++-----
> gcc/cp/pt.cc | 29 +++++++----
> gcc/cp/semantics.cc | 45 ++++++++++++-----
> gcc/cp/tree.cc | 22 ++++++--
> gcc/cp/typeck.cc | 7 ++-
> gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C | 4 +-
> gcc/testsuite/g++.dg/ext/underlying_type13.C | 7 +++
> gcc/testsuite/g++.dg/ext/underlying_type14.C | 8 +++
> gcc/testsuite/g++.dg/ext/underlying_type7.C | 2 +-
> 17 files changed, 197 insertions(+), 78 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type13.C
> create mode 100644 gcc/testsuite/g++.dg/ext/underlying_type14.C
>
> diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
> index 64975699351..380f288a7f1 100644
> --- a/gcc/cp/cp-objcp-common.cc
> +++ b/gcc/cp/cp-objcp-common.cc
> @@ -518,7 +518,7 @@ cp_common_init_ts (void)
> MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE);
> MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE);
> MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE);
> - MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE);
> + MARK_TS_TYPE_NON_COMMON (TRAIT_TYPE);
> MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM);
> MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM);
> MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM);
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index f9cbd339f19..f83b4c54d43 100644
> --- a/gcc/cp/cp-tree.def
> +++ b/gcc/cp/cp-tree.def
> @@ -444,9 +444,12 @@ DEFTREECODE (BIT_CAST_EXPR, "bit_cast_expr", tcc_expression, 1)
>
> /** C++ extensions. */
>
> -/* Represents a trait expression during template expansion. */
> +/* Represents a templated trait that yields an expression. */
> DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
>
> +/* Represents a templated trait that yields a type. */
> +DEFTREECODE (TRAIT_TYPE, "trait_type", tcc_type, 0)
> +
> /* A lambda expression. This is a C++0x extension.
> LAMBDA_EXPR_DEFAULT_CAPTURE_MODE is an enum for the default, which may be
> none.
> @@ -466,10 +469,6 @@ DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
> DECLTYPE_FOR_LAMBDA_RETURN is set if we want lambda return deduction. */
> DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
>
> -/* A type designated by `__underlying_type (type)'.
> - UNDERLYING_TYPE_TYPE is the type in question. */
> -DEFTREECODE (UNDERLYING_TYPE, "underlying_type", tcc_type, 0)
> -
> /* A type designated by one of the bases type traits.
> BASES_TYPE is the type in question. */
> DEFTREECODE (BASES, "bases", tcc_type, 0)
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 19bbfbc557f..a89baa8d232 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1436,6 +1436,22 @@ struct GTY (()) tree_trait_expr {
> enum cp_trait_kind kind;
> };
>
> +/* An INTEGER_CST containing the kind of the trait type NODE. */
> +#define TRAIT_TYPE_KIND_RAW(NODE) \
> + TYPE_VALUES_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The kind of the trait type NODE. */
> +#define TRAIT_TYPE_KIND(NODE) \
> + ((enum cp_trait_kind) TREE_INT_CST_LOW (TRAIT_TYPE_KIND_RAW (NODE)))
> +
> +/* The first argument of the trait type NODE. */
> +#define TRAIT_TYPE_TYPE1(NODE) \
> + TYPE_MIN_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> +/* The rest of the arguments of the trait type NODE. */
> +#define TRAIT_TYPE_TYPE2(NODE) \
> + TYPE_MAX_VALUE_RAW (TRAIT_TYPE_CHECK (NODE))
> +
> /* Identifiers used for lambda types are almost anonymous. Use this
> spare flag to distinguish them (they also have the anonymous flag). */
> #define IDENTIFIER_LAMBDA_P(NODE) \
> @@ -2225,6 +2241,7 @@ enum languages { lang_c, lang_cplusplus };
> || TREE_CODE (T) == TYPEOF_TYPE \
> || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \
> || TREE_CODE (T) == DECLTYPE_TYPE \
> + || TREE_CODE (T) == TRAIT_TYPE \
> || TREE_CODE (T) == DEPENDENT_OPERATOR_TYPE)
>
> /* Nonzero if T is a class (or struct or union) type. Also nonzero
> @@ -7731,6 +7748,7 @@ extern tree finish_decltype_type (tree, bool, tsubst_flags_t);
> extern tree fold_builtin_is_corresponding_member (location_t, int, tree *);
> extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *);
> extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree);
> +extern tree finish_trait_type (enum cp_trait_kind, tree, tree);
> extern tree build_lambda_expr (void);
> extern tree build_lambda_object (tree);
> extern tree begin_lambda_type (tree);
> diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
> index e18143e39a9..928c58e0f67 100644
> --- a/gcc/cp/cxx-pretty-print.cc
> +++ b/gcc/cp/cxx-pretty-print.cc
> @@ -483,7 +483,7 @@ cxx_pretty_printer::primary_expression (tree t)
> break;
>
> case TRAIT_EXPR:
> - pp_cxx_trait_expression (this, t);
> + pp_cxx_trait (this, t);
> break;
>
> case VA_ARG_EXPR:
> @@ -1240,7 +1240,7 @@ cxx_pretty_printer::expression (tree t)
> break;
>
> case TRAIT_EXPR:
> - pp_cxx_trait_expression (this, t);
> + pp_cxx_trait (this, t);
> break;
>
> case ATOMIC_CONSTR:
> @@ -1385,6 +1385,10 @@ cxx_pretty_printer::simple_type_specifier (tree t)
> pp_cxx_ws_string (this, "std::nullptr_t");
> break;
>
> + case TRAIT_TYPE:
> + pp_cxx_trait (this, t);
> + break;
> +
> default:
> c_pretty_printer::simple_type_specifier (t);
> break;
> @@ -1876,7 +1880,7 @@ cxx_pretty_printer::type_id (tree t)
> case TEMPLATE_PARM_INDEX:
> case TEMPLATE_DECL:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> + case TRAIT_TYPE:
> case DECLTYPE_TYPE:
> case NULLPTR_TYPE:
> case TEMPLATE_ID_EXPR:
> @@ -2594,9 +2598,22 @@ pp_cxx_binary_fold_expression (cxx_pretty_printer *pp, tree t)
> }
>
> void
> -pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
> +pp_cxx_trait (cxx_pretty_printer *pp, tree t)
> {
> - cp_trait_kind kind = TRAIT_EXPR_KIND (t);
> + cp_trait_kind kind;
> + tree type1, type2;
> + if (TREE_CODE (t) == TRAIT_EXPR)
> + {
> + kind = TRAIT_EXPR_KIND (t);
> + type1 = TRAIT_EXPR_TYPE1 (t);
> + type2 = TRAIT_EXPR_TYPE2 (t);
> + }
> + else
> + {
> + kind = TRAIT_TYPE_KIND (t);
> + type1 = TRAIT_TYPE_TYPE1 (t);
> + type2 = TRAIT_TYPE_TYPE2 (t);
> + }
>
> switch (kind)
> {
> @@ -2708,23 +2725,29 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
> 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;
> default:
> gcc_unreachable ();
> }
>
> pp_cxx_left_paren (pp);
> - pp->type_id (TRAIT_EXPR_TYPE1 (t));
> -
> - if (kind == CPTK_IS_BASE_OF
> - || kind == CPTK_IS_SAME_AS
> - || kind == CPTK_IS_LAYOUT_COMPATIBLE
> - || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF)
> + pp->type_id (type1);
> + if (type2)
> {
> - pp_cxx_separate_with (pp, ',');
> - pp->type_id (TRAIT_EXPR_TYPE2 (t));
> + if (TREE_CODE (type2) != TREE_LIST)
> + {
> + pp_cxx_separate_with (pp, ',');
> + pp->type_id (type2);
> + }
> + else
> + for (tree arg = type2; arg; arg = TREE_CHAIN (arg))
> + {
> + pp_cxx_separate_with (pp, ',');
> + pp->type_id (TREE_VALUE (arg));
> + }
> }
> -
> pp_cxx_right_paren (pp);
> }
>
> diff --git a/gcc/cp/cxx-pretty-print.h b/gcc/cp/cxx-pretty-print.h
> index 593bd91d4f7..25a2c7c8d4a 100644
> --- a/gcc/cp/cxx-pretty-print.h
> +++ b/gcc/cp/cxx-pretty-print.h
> @@ -90,7 +90,7 @@ void pp_cxx_colon_colon (cxx_pretty_printer *);
> void pp_cxx_separate_with (cxx_pretty_printer *, int);
>
> void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
> -void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
> +void pp_cxx_trait (cxx_pretty_printer *, tree);
> void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
> void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
> void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 0389f35d731..4bf9a83f20b 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -698,12 +698,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
> pp_cxx_right_paren (pp);
> break;
>
> - case UNDERLYING_TYPE:
> - pp_cxx_ws_string (pp, "__underlying_type");
> - pp_cxx_whitespace (pp);
> - pp_cxx_left_paren (pp);
> - dump_expr (pp, UNDERLYING_TYPE_TYPE (t), flags & ~TFF_EXPR_IN_PARENS);
> - pp_cxx_right_paren (pp);
> + case TRAIT_TYPE:
> + pp_cxx_trait (pp, t);
> break;
>
> case TYPE_PACK_EXPANSION:
> @@ -971,7 +967,7 @@ dump_type_prefix (cxx_pretty_printer *pp, tree t, int flags)
> case COMPLEX_TYPE:
> case VECTOR_TYPE:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> + case TRAIT_TYPE:
> case DECLTYPE_TYPE:
> case TYPE_PACK_EXPANSION:
> case FIXED_POINT_TYPE:
> @@ -1095,7 +1091,7 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
> case COMPLEX_TYPE:
> case VECTOR_TYPE:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> + case TRAIT_TYPE:
> case DECLTYPE_TYPE:
> case TYPE_PACK_EXPANSION:
> case FIXED_POINT_TYPE:
> @@ -2956,7 +2952,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
> break;
>
> case TRAIT_EXPR:
> - pp_cxx_trait_expression (pp, t);
> + pp_cxx_trait (pp, t);
> break;
>
> case VA_ARG_EXPR:
> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> index 00d283fff8c..fc750fc5d8e 100644
> --- a/gcc/cp/mangle.cc
> +++ b/gcc/cp/mangle.cc
> @@ -2389,8 +2389,9 @@ write_type (tree type)
> sorry ("mangling %<typeof%>, use %<decltype%> instead");
> break;
>
> - case UNDERLYING_TYPE:
> - sorry ("mangling %<__underlying_type%>");
> + case TRAIT_TYPE:
> + error ("use of built-in trait %qT in function signature; "
> + "use library traits instead", type);
> break;
>
> case LANG_TYPE:
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 7496df5e843..25741e5d827 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -8910,7 +8910,6 @@ trees_out::type_node (tree type)
>
> case DECLTYPE_TYPE:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> case DEPENDENT_OPERATOR_TYPE:
> tree_node (TYPE_VALUES_RAW (type));
> if (TREE_CODE (type) == DECLTYPE_TYPE)
> @@ -8920,6 +8919,12 @@ trees_out::type_node (tree type)
> tree_node_bools (type);
> break;
>
> + case TRAIT_TYPE:
> + tree_node (TRAIT_TYPE_KIND_RAW (type));
> + tree_node (TRAIT_TYPE_TYPE1 (type));
> + tree_node (TRAIT_TYPE_TYPE2 (type));
> + break;
> +
> case TYPE_ARGUMENT_PACK:
> /* No additional data. */
> break;
> @@ -9434,7 +9439,6 @@ trees_in::tree_node (bool is_use)
>
> case DECLTYPE_TYPE:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> case DEPENDENT_OPERATOR_TYPE:
> {
> tree expr = tree_node ();
> @@ -9449,6 +9453,22 @@ trees_in::tree_node (bool is_use)
> }
> break;
>
> + case TRAIT_TYPE:
> + {
> + tree kind = tree_node ();
> + tree type1 = tree_node ();
> + tree type2 = tree_node ();
> + if (!get_overrun ())
> + {
> + res = cxx_make_type (TRAIT_TYPE);
> + TRAIT_TYPE_KIND_RAW (res) = kind;
> + TRAIT_TYPE_TYPE1 (res) = type1;
> + TRAIT_TYPE_TYPE2 (res) = type2;
> + SET_TYPE_STRUCTURAL_EQUALITY (res);
> + }
> + }
> + break;
> +
> case TYPE_ARGUMENT_PACK:
> if (!get_overrun ())
> {
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index d501178634a..9f5e2c292b3 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -2783,7 +2783,7 @@ static void cp_parser_late_parsing_default_args
> (cp_parser *, tree);
> static tree cp_parser_sizeof_operand
> (cp_parser *, enum rid);
> -static cp_expr cp_parser_trait_expr
> +static cp_expr cp_parser_trait
> (cp_parser *, enum rid);
> static bool cp_parser_declares_only_class_p
> (cp_parser *);
> @@ -5928,7 +5928,7 @@ cp_parser_primary_expression (cp_parser *parser,
> case RID_IS_NOTHROW_CONVERTIBLE:
> case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
> case RID_REF_CONVERTS_FROM_TEMPORARY:
> - return cp_parser_trait_expr (parser, token->keyword);
> + return cp_parser_trait (parser, token->keyword);
>
> // C++ concepts
> case RID_REQUIRES:
> @@ -10882,18 +10882,16 @@ cp_parser_builtin_offsetof (cp_parser *parser)
> return expr;
> }
>
> -/* Parse a trait expression.
> -
> - Returns a representation of the expression, the underlying type
> - of the type at issue when KEYWORD is RID_UNDERLYING_TYPE. */
> +/* Parse a builtin trait expression or type. */
>
> static cp_expr
> -cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
> +cp_parser_trait (cp_parser* parser, enum rid keyword)
> {
> cp_trait_kind kind;
> tree type1, type2 = NULL_TREE;
> bool binary = false;
> bool variadic = false;
> + bool type = false;
>
> switch (keyword)
> {
> @@ -10989,6 +10987,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
> break;
> case RID_UNDERLYING_TYPE:
> kind = CPTK_UNDERLYING_TYPE;
> + type = true;
> break;
> case RID_BASES:
> kind = CPTK_BASES;
> @@ -11092,14 +11091,15 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
> the trait expr now or saving it for template instantiation. */
> switch (kind)
> {
> - case CPTK_UNDERLYING_TYPE:
> - return cp_expr (finish_underlying_type (type1), trait_loc);
> case CPTK_BASES:
> return cp_expr (finish_bases (type1, false), trait_loc);
> case CPTK_DIRECT_BASES:
> return cp_expr (finish_bases (type1, true), trait_loc);
> default:
> - return finish_trait_expr (trait_loc, kind, type1, type2);
> + if (type)
> + return finish_trait_type (kind, type1, type2);
> + else
> + return finish_trait_expr (trait_loc, kind, type1, type2);
> }
> }
>
> @@ -19867,7 +19867,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
> return type;
>
> case RID_UNDERLYING_TYPE:
> - type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
> + type = cp_parser_trait (parser, token->keyword);
> if (decl_specs)
> cp_parser_set_decl_spec_type (decl_specs, type,
> token,
> @@ -19877,7 +19877,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>
> case RID_BASES:
> case RID_DIRECT_BASES:
> - type = cp_parser_trait_expr (parser, token->keyword);
> + type = cp_parser_trait (parser, token->keyword);
> if (decl_specs)
> cp_parser_set_decl_spec_type (decl_specs, type,
> token,
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 2d83dfd6954..cf8d8d50d63 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -10618,7 +10618,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
>
> case TYPEOF_TYPE:
> case DECLTYPE_TYPE:
> - case UNDERLYING_TYPE:
> if (pfd->include_nondeduced_p
> && for_each_template_parm (TYPE_VALUES_RAW (t), fn, data,
> pfd->visited,
> @@ -10628,6 +10627,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
> *walk_subtrees = false;
> break;
>
> + case TRAIT_TYPE:
> + if (pfd->include_nondeduced_p)
> + {
> + WALK_SUBTREE (TRAIT_TYPE_TYPE1 (t));
> + WALK_SUBTREE (TRAIT_TYPE_TYPE2 (t));
> + }
> + *walk_subtrees = false;
> + break;
> +
> case FUNCTION_DECL:
> case VAR_DECL:
> if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
> @@ -16514,11 +16522,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
> complain | tf_ignore_bad_quals);
> }
>
> - case UNDERLYING_TYPE:
> + case TRAIT_TYPE:
> {
> - tree type = tsubst (UNDERLYING_TYPE_TYPE (t), args,
> - complain, in_decl);
> - return finish_underlying_type (type);
> + tree type1 = tsubst (TRAIT_TYPE_TYPE1 (t), args, complain, in_decl);
> + tree type2 = tsubst (TRAIT_TYPE_TYPE2 (t), args, complain, in_decl);
> + type = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
> + return cp_build_qualified_type (type,
> + cp_type_quals (t) | cp_type_quals (type),
> + complain | tf_ignore_bad_quals);
> }
>
> case TYPE_ARGUMENT_PACK:
> @@ -24928,9 +24939,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
>
> case TYPEOF_TYPE:
> case DECLTYPE_TYPE:
> - case UNDERLYING_TYPE:
> + case TRAIT_TYPE:
> /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
> - or UNDERLYING_TYPE nodes. */
> + or TRAIT_TYPE nodes. */
> return unify_success (explain_p);
>
> case ERROR_MARK:
> @@ -27505,12 +27516,12 @@ dependent_type_p_r (tree type)
> (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
> return true;
>
> - /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and UNDERLYING_TYPEs are
> + /* All TYPEOF_TYPEs, DECLTYPE_TYPEs, and TRAIT_TYPEs are
> dependent; if the argument of the `typeof' expression is not
> type-dependent, then it should already been have resolved. */
> if (TREE_CODE (type) == TYPEOF_TYPE
> || TREE_CODE (type) == DECLTYPE_TYPE
> - || TREE_CODE (type) == UNDERLYING_TYPE)
> + || TREE_CODE (type) == TRAIT_TYPE)
> return true;
>
> /* A template argument pack is dependent if any of its packed
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index e8cd50558d6..73144ef04b8 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -4397,17 +4397,6 @@ finish_typeof (tree expr)
> tree
> finish_underlying_type (tree type)
> {
> - tree underlying_type;
> -
> - if (processing_template_decl)
> - {
> - underlying_type = cxx_make_type (UNDERLYING_TYPE);
> - UNDERLYING_TYPE_TYPE (underlying_type) = type;
> - SET_TYPE_STRUCTURAL_EQUALITY (underlying_type);
> -
> - return underlying_type;
> - }
> -
> if (!complete_type_or_else (type, NULL_TREE))
> return error_mark_node;
>
> @@ -4417,7 +4406,7 @@ finish_underlying_type (tree type)
> return error_mark_node;
> }
>
> - underlying_type = ENUM_UNDERLYING_TYPE (type);
> + tree underlying_type = ENUM_UNDERLYING_TYPE (type);
>
> /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
> includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
> @@ -12224,6 +12213,38 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
> return maybe_wrap_with_location (val, loc);
> }
>
> +/* Process a trait type. */
> +
> +tree
> +finish_trait_type (cp_trait_kind kind, tree type1, tree type2)
> +{
> + if (type1 == error_mark_node
> + || type2 == error_mark_node)
> + return error_mark_node;
> +
> + if (processing_template_decl)
> + {
> + tree type = cxx_make_type (TRAIT_TYPE);
> + TRAIT_TYPE_TYPE1 (type) = type1;
> + TRAIT_TYPE_TYPE2 (type) = type2;
> + TRAIT_TYPE_KIND_RAW (type) = build_int_cstu (integer_type_node, kind);
> + /* These traits are intended to be used in the definition of the ::type
> + member of the corresponding standard library type trait (and thus won't
> + appear directly in template signatures), so structural equality should
> + suffice. */
> + SET_TYPE_STRUCTURAL_EQUALITY (type);
> + return type;
> + }
> +
> + switch (kind)
> + {
> + case CPTK_UNDERLYING_TYPE:
> + return finish_underlying_type (type1);
> + default:
> + gcc_unreachable ();
> + }
> +}
> +
> /* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64,
> which is ignored for C++. */
>
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index ea4dfc651bb..aa9c1b7d8f9 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -1776,10 +1776,17 @@ strip_typedefs (tree t, bool *remove_attributes /* = NULL */,
> DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t),
> tf_none));
> break;
> - case UNDERLYING_TYPE:
> - type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
> - remove_attributes, flags);
> - result = finish_underlying_type (type);
> + case TRAIT_TYPE:
> + {
> + tree type1 = strip_typedefs (TRAIT_TYPE_TYPE1 (t),
> + remove_attributes, flags);
> + tree type2 = strip_typedefs (TRAIT_TYPE_TYPE2 (t),
> + remove_attributes, flags);
> + if (type1 == TRAIT_TYPE_TYPE1 (t) && type2 == TRAIT_TYPE_TYPE2 (t))
> + result = NULL_TREE;
> + else
> + result = finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2);
> + }
> break;
> case TYPE_PACK_EXPANSION:
> {
> @@ -5383,7 +5390,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
> case UNBOUND_CLASS_TEMPLATE:
> case TEMPLATE_PARM_INDEX:
> case TYPEOF_TYPE:
> - case UNDERLYING_TYPE:
> /* None of these have subtrees other than those already walked
> above. */
> *walk_subtrees_p = 0;
> @@ -5472,6 +5478,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
> *walk_subtrees_p = 0;
> break;
>
> + case TRAIT_TYPE:
> + WALK_SUBTREE (TRAIT_TYPE_TYPE1 (*tp));
> + WALK_SUBTREE (TRAIT_TYPE_TYPE2 (*tp));
> + *walk_subtrees_p = 0;
> + break;
> +
> case DECLTYPE_TYPE:
> ++cp_unevaluated_operand;
> /* We can't use WALK_SUBTREE here because of the goto. */
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index 5f16c4d2426..cecf825f5e6 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -1621,8 +1621,11 @@ structural_comptypes (tree t1, tree t2, int strict)
> return false;
> break;
>
> - case UNDERLYING_TYPE:
> - if (!same_type_p (UNDERLYING_TYPE_TYPE (t1), UNDERLYING_TYPE_TYPE (t2)))
> + case TRAIT_TYPE:
> + if (TRAIT_TYPE_KIND (t1) != TRAIT_TYPE_KIND (t2))
> + return false;
> + if (!same_type_p (TRAIT_TYPE_TYPE1 (t1), TRAIT_TYPE_TYPE1 (t2))
> + || !cp_tree_equal (TRAIT_TYPE_TYPE2 (t1), TRAIT_TYPE_TYPE2 (t2)))
> return false;
> break;
>
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> index 1f5e94f6d83..50946576f74 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-59.C
> @@ -5,7 +5,7 @@ template<typename>
> struct A {};
>
> template<typename T>
> -using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::aligned(4)]]>; // { dg-warning "ignoring attributes applied to dependent type" }
>
> template<typename T>
> -using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes on template argument" }
> +using B = A<__underlying_type(T) [[gnu::packed]]>; // { dg-warning "ignoring attributes applied to dependent type" }
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type13.C b/gcc/testsuite/g++.dg/ext/underlying_type13.C
> new file mode 100644
> index 00000000000..c53da11eb8a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type13.C
> @@ -0,0 +1,7 @@
> +// Verify when substituting __underlying_type its cv-quals are carried over.
> +// { dg-do compile { target c++11 } }
> +
> +template<class T> using const_underlying_type_t = const __underlying_type(T);
> +enum A { a };
> +using type = const_underlying_type_t<A>;
> +using type = const __underlying_type(A);
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type14.C b/gcc/testsuite/g++.dg/ext/underlying_type14.C
> new file mode 100644
> index 00000000000..91840b2015c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type14.C
> @@ -0,0 +1,8 @@
> +// Verify pretty-printing when nesting a builtin trait.
> +
> +template<class T> void f(__underlying_type(__underlying_type(T))); // { dg-error "" }
> +// { dg-message "__underlying_type\\(__underlying_type\\(T\\)\\)\\)" "" { target *-*-* } .-1 }
> +
> +int main() {
> + f<int>(0); // { dg-error "no match" }
> +}
> diff --git a/gcc/testsuite/g++.dg/ext/underlying_type7.C b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> index 2d6ec51792c..137a0f08547 100644
> --- a/gcc/testsuite/g++.dg/ext/underlying_type7.C
> +++ b/gcc/testsuite/g++.dg/ext/underlying_type7.C
> @@ -9,7 +9,7 @@ enum class E6 : long { c = __LONG_MAX__ };
>
> template<typename T>
> void
> - test(T, __underlying_type(T)) // { dg-message "sorry, unimplemented: mangling" }
> + test(T, __underlying_type(T)) // { dg-error "built-in trait '__underlying_type\\(T\\)'" }
> { }
>
> int main()
prev parent reply other threads:[~2022-09-28 18:49 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-27 19:50 Patrick Palka
2022-09-27 19:50 ` [PATCH 2/2] c++: implement __remove_cv, __remove_reference and __remove_cvref Patrick Palka
2022-09-27 20:27 ` Jonathan Wakely
2022-09-27 21:09 ` Jason Merrill
2022-09-27 21:07 ` [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR Jason Merrill
2022-09-28 16:36 ` Patrick Palka
2022-09-28 18:49 ` Jason Merrill [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4276ddd3-63e9-adc1-e448-09bfb5d7056a@redhat.com \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
--cc=ppalka@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).