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 7036D3858016 for ; Wed, 28 Sep 2022 16:37:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7036D3858016 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=1664383024; 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: in-reply-to:in-reply-to:references:references; bh=ppeGi5QQnnw+6yn+MD/MZz4wMKI0jMx25jTX2iaKjuk=; b=AgPdziuNryBbgfy/p+H/hd61I6MlHI70LPizKP5ZE3mlNUWLd5K/PKL33R5EzoOeAXiMQr CacDcvqpBikH+ZkKUp2mAMvHnXq/X3D4moq3hnwQ7TmLcQiSTefwfy0YEFr9SEVP024QKX rLQcoUtrED70nTRGxu7ray9YQdQ1yfE= Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-436-gtJ9Y5nvPVaDOe-zQB76qw-1; Wed, 28 Sep 2022 12:37:03 -0400 X-MC-Unique: gtJ9Y5nvPVaDOe-zQB76qw-1 Received: by mail-qk1-f200.google.com with SMTP id w10-20020a05620a444a00b006ce9917ea1fso9933861qkp.16 for ; Wed, 28 Sep 2022 09:37:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:references:message-id:in-reply-to:subject:cc:to:date :from:x-gm-message-state:from:to:cc:subject:date; bh=ppeGi5QQnnw+6yn+MD/MZz4wMKI0jMx25jTX2iaKjuk=; b=a0Qh36Y6RwKWFAgzCpFesuuDIJsRmKl5sefNo+zOo75E0VaCwsyVzszscMCTrdh27w OgpqCmVhPFhXYyeBq9y71icqglYtSXRq9v0q9RPdLRwBEqhux+qomBlyxoV2Y2gSqBeM 0NMkcGk5ycNj6T0agmCqNG5/7x1GlCX7gMRbhcBPH8oofnY8es31sVHic1mvsuPJHvWu 8sLPhey0UqyilAssUGUg+eKHFUjxsD/g1mZ9m6Ppx5cNmGhxYfK3R7yGcQWJ9SUm/pby VVPYeMOj9lXBhmADsT4HnkCKWG4/88Q+bP+525gNS5xLGGg9bpUMMjJmcQzeETNu9ol+ OKzw== X-Gm-Message-State: ACrzQf3wEOO1Y+dQD3cJc8duHu7UWonY8cQTQIRWHkAf8WETrIvIZ0tQ Uky3ffrjXE5GO0IfTmNgps9BlIZPZ4G+1q84Y5xC8W1Yn9lP9YaciFKwuj0dNZFUnQkiQrpo486 znZu+5lhd8gdrjf8= X-Received: by 2002:a05:620a:2698:b0:6cf:38bb:f705 with SMTP id c24-20020a05620a269800b006cf38bbf705mr22396950qkp.130.1664383021685; Wed, 28 Sep 2022 09:37:01 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6n9V27sgT8Tq4/+SqdL7ybk//mRe5EvDQDh97PaNOzI5ZKZrKtj7v2e94f6mXoHCVnAWjBCQ== X-Received: by 2002:a05:620a:2698:b0:6cf:38bb:f705 with SMTP id c24-20020a05620a269800b006cf38bbf705mr22396912qkp.130.1664383021076; Wed, 28 Sep 2022 09:37:01 -0700 (PDT) Received: from [192.168.1.130] (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id f7-20020a05620a408700b006ce3f1af120sm3524701qko.44.2022.09.28.09.36.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Sep 2022 09:37:00 -0700 (PDT) From: Patrick Palka X-Google-Original-From: Patrick Palka Date: Wed, 28 Sep 2022 12:36:59 -0400 (EDT) To: Jason Merrill cc: Patrick Palka , gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Subject: Re: [PATCH 1/2] c++: introduce TRAIT_TYPE alongside TRAIT_EXPR In-Reply-To: Message-ID: References: <20220927195030.2024439-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-14.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,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 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? > > > + > > /* 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. -- >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() -- 2.38.0.rc2