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 DFE643858036 for ; Tue, 27 Sep 2022 21:07:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DFE643858036 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=1664312850; 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=72uU00ef2qJqGE4bwrzyZwPOUYuAz9fKXX4hccdi43I=; b=C7pRdSV6Jv47IiDlOtCY7aXQVcoabRl59+p4JPKXxt9AUCojngWzp0pMSBZf9FdaxGikDm 21xoxDQnx54ivU14lgxL8hAwqOUfiKzXmQ7jvinZszlR20XkeFAj5p89NiEyZBFYib5cXB lLvYvq0QLdv6zBylIZk1bjpfudaOQ9A= Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-502-kqNRPzU3NM2U2LREThw4Cg-1; Tue, 27 Sep 2022 17:07:29 -0400 X-MC-Unique: kqNRPzU3NM2U2LREThw4Cg-1 Received: by mail-qt1-f198.google.com with SMTP id ew15-20020a05622a514f00b0035cb76e35e5so7580440qtb.7 for ; Tue, 27 Sep 2022 14:07:29 -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=72uU00ef2qJqGE4bwrzyZwPOUYuAz9fKXX4hccdi43I=; b=4Esd0rg/+2N5w1P6msgzCA2AVW8iD4djHACzABglymmaxKqJtphK4TcPGLOZzrDIgj WPsKXWPeS2gGNVX3BCIobRxf9qq+D3B7uwEU1ithsOSAu7o8LxrulcQ+cX0YwmcoYfhW wkgrx4J7aI0VBfjKPy//LeGFf82h3ONcfIzbGy+PMC/a5Fk+/7ngDpgKjxF8+BnITiEz K0OO81GgsQjE/4PEq1jai4b9/h36DxhhNjHZkaPG+iqkecqYzw5ejueuD6asO0/uUpNN HO499dLPCaGiWH6XVwNedcU2DlTFWdlGfNrQ6mT6x0Y3eVSSCycDUSLTqcfyAjToP2lx Y9Ng== X-Gm-Message-State: ACrzQf2L8aWxf3SNSwbB7S/WGlD0bbULb6OtmW1tt0b0uZlczNZxtyJ/ U9cO2Y4swDzKcuPaU+XAJxsCU4tHq7WRAMXajWBojaCwCxogPdhQYyCEzEtaiSl6OiTwfAuKPcy +29QuGfu/AemPI3c= X-Received: by 2002:a05:622a:1654:b0:35b:a47b:4935 with SMTP id y20-20020a05622a165400b0035ba47b4935mr24163820qtj.288.1664312848120; Tue, 27 Sep 2022 14:07:28 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6E/x3Rd3jFXtZwCJYq/ED306UsYG+bUMDfYexm4q8PsR+s7Mz2I6M0f0YCLAMb3zPQJ7JmIg== X-Received: by 2002:a05:622a:1654:b0:35b:a47b:4935 with SMTP id y20-20020a05622a165400b0035ba47b4935mr24163784qtj.288.1664312847648; Tue, 27 Sep 2022 14:07:27 -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 d14-20020ac800ce000000b00342f8143599sm1580893qtg.13.2022.09.27.14.07.26 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 27 Sep 2022 14:07:27 -0700 (PDT) Message-ID: Date: Tue, 27 Sep 2022 17:07:26 -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 , gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org References: <20220927195030.2024439-1-ppalka@redhat.com> From: Jason Merrill In-Reply-To: <20220927195030.2024439-1-ppalka@redhat.com> 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/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... > 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? > + > /* 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. > 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. > + } > + } > + 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 30c6994bae1..1a4491d3556 100644 > --- a/gcc/cp/pt.cc > +++ b/gcc/cp/pt.cc > @@ -10619,7 +10619,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, > @@ -10629,6 +10628,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)) > @@ -16515,11 +16523,11 @@ 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); > + return finish_trait_type (TRAIT_TYPE_KIND (t), type1, type2); > } > > case TYPE_ARGUMENT_PACK: > @@ -24929,9 +24937,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: > @@ -27506,12 +27514,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..ea00805c97d 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,34 @@ 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); > + 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 d0bd41ae5a0..eef694689cc 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 4854b983765..5064a009af0 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_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()