From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 013B938582B1 for ; Wed, 28 Sep 2022 18:49:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 013B938582B1 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1664390980; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=E60VUBeb+4k+grwjY/IYLLPUhVDYOajRGgQyt0swP48=; b=WLWfULCJXWGxpzfRtxhWcAhdiFO0fhaFn5YJexJ5cFb1JoTgR9e9ZOoz69w/+cJrZ9cYYN fDWdgxiCkzvtY0tqy1UAAW8/ot6l+hMwLlK5OQUQPsw59u/azMlRCVXrIn+HUtEYgLO7Ml QH5sqG4CrAXfMHJUSuVJCzZfr8RATU4= Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-176-kL9k196qN_i1yriNCF1yhQ-1; Wed, 28 Sep 2022 14:49:39 -0400 X-MC-Unique: kL9k196qN_i1yriNCF1yhQ-1 Received: by mail-qk1-f198.google.com with SMTP id w10-20020a05620a444a00b006ce9917ea1fso10205910qkp.16 for ; Wed, 28 Sep 2022 11:49:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date; bh=E60VUBeb+4k+grwjY/IYLLPUhVDYOajRGgQyt0swP48=; b=R0h6pfpsQYp7DgV+eZlEaX/I+RipgDl2Owc/79wupDIU2NmJZ1JTqgOZWxBs8oQPy4 seKW6IPnpKMVYAlV/UYgCQZaLBMoE7CgQfzvqJ9UjxeS59wJrow4Eb7tycgchqsRaD8b 6B5I6fkTkWWPIJbXGyuPjPJT2Y6zPB7mlH7Zh8eYtdydwKslEYr4R0d0I7GM+8W77cSw zbgANLgaKyC21m5Bp1GpIeWfjvOK6/GyGeTMhZn8QQnvbI0fU6oQZhSiZ93PDRd7A6XL CbOl9g+Zev3gyZmGZPBGFgWCMYBdBx6PpXca7JxBwE/vwPnYpbS0judeh54Ddp4qBxzd 3AFw== X-Gm-Message-State: ACrzQf2TIyJJM7aPM5T23THCt8X0erxy0V9jJ2uvh8YRgXtiFyZLS78e vv5MmwBcrHwUkVMSnhEOiE99EJP8Ng8tCfQynE5pnm8Uz3aF/PeOwEROHwc3uW51i7tTpQRdZj4 ZdB5i/yiSzMfcL/Xc3Q== X-Received: by 2002:ac8:5a55:0:b0:35c:e303:e45f with SMTP id o21-20020ac85a55000000b0035ce303e45fmr28743410qta.419.1664390978178; Wed, 28 Sep 2022 11:49:38 -0700 (PDT) X-Google-Smtp-Source: AMsMyM4u4+5dWC93dcpUw05qGLcTdS/UJ9hXi6G+KrASD33WQ12rz5fjN+M1qsdnzSzyeoFfbpGL+w== X-Received: by 2002:ac8:5a55:0:b0:35c:e303:e45f with SMTP id o21-20020ac85a55000000b0035ce303e45fmr28743380qta.419.1664390977490; Wed, 28 Sep 2022 11:49:37 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id w14-20020ac84d0e000000b0035cd6a4ba3csm3325634qtv.39.2022.09.28.11.49.36 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 28 Sep 2022 11:49:36 -0700 (PDT) Message-ID: <4276ddd3-63e9-adc1-e448-09bfb5d7056a@redhat.com> Date: Wed, 28 Sep 2022 14:49:35 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.1 Subject: Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR To: Patrick Palka Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org References: <20220927195030.2024439-1-ppalka@redhat.com> From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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) : Remove. >>> : New. >>> (dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE. >>> (dump_type_suffix): Likewise. >>> * mangle.cc (write_type) : Remove. >>> : New. >>> * module.cc (trees_out::type_node) : >>> Remove. >>> : 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) : >>> Remove. >>> : 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) : Remove. >>> : 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 %, use % 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) : > 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) : Remove. > : New. > (dump_type_prefix): Replace UNDERLYING_WITH with TRAIT_TYPE. > (dump_type_suffix): Likewise. > * mangle.cc (write_type) : Remove. > : New. > * module.cc (trees_out::type_node) : > Remove. > : 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) : > Remove. > : 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) : Remove. > : 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 %, use % 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 > struct A {}; > > template > -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 > -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 using const_underlying_type_t = const __underlying_type(T); > +enum A { a }; > +using type = const_underlying_type_t; > +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 void f(__underlying_type(__underlying_type(T))); // { dg-error "" } > +// { dg-message "__underlying_type\\(__underlying_type\\(T\\)\\)\\)" "" { target *-*-* } .-1 } > + > +int main() { > + f(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 > 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()