From patchwork Tue Sep 10 02:19:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Butcher X-Patchwork-Id: 273748 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "www.sourceware.org", Issuer "StartCom Class 1 Primary Intermediate Server CA" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 1BA9E2C00AC for ; Tue, 10 Sep 2013 12:21:04 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=xtXKIH6do9IrXKPdcWVbv58IEeqcsCSihPUZMTNhlFnFj57Rd4MYG hZxAc41qS3LeMCoYoQ/pBKY2/E4CBrNh4so3qpSqvl35nKj/e3jOn6fuUTpxrUpG wEdjWejyZcH5+MSGUV30JlI4RCIKG/eveq51yLkDRINd1Z1UztqpQM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=zauNpNHLLg4CWzYjg4l9YMXOgFQ=; b=y15aCSJfDmrItrj808K2 sbm4MMU+wd8YM03BfpCxla1XfH8PL19/Ifq8gFdKcBL2cOeL2v7/ofc5pepyw0ig 58des68AcynWtbNRT0ulHg+dqDOuLHFDtlHgdrI5oWpb7Z2alMKVDeqVajtyI4Ro s7pZWtA6RkKfxZC6Uaro170= Received: (qmail 29579 invoked by alias); 10 Sep 2013 02:20:34 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 29548 invoked by uid 89); 10 Sep 2013 02:20:34 -0000 Received: from mail-ea0-f182.google.com (HELO mail-ea0-f182.google.com) (209.85.215.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 10 Sep 2013 02:20:34 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.5 required=5.0 tests=ALL_TRUSTED, AWL, BAYES_00, FREEMAIL_FROM, KHOP_THREADED autolearn=ham version=3.3.2 X-HELO: mail-ea0-f182.google.com Received: by mail-ea0-f182.google.com with SMTP id o10so3549205eaj.13 for ; Mon, 09 Sep 2013 19:20:27 -0700 (PDT) X-Received: by 10.15.35.196 with SMTP id g44mr35203935eev.18.1378779627829; Mon, 09 Sep 2013 19:20:27 -0700 (PDT) Received: from sphere.lan (munkyhouse.force9.co.uk. [84.92.244.81]) by mx.google.com with ESMTPSA id bn13sm27020393eeb.11.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 09 Sep 2013 19:20:27 -0700 (PDT) From: Adam Butcher To: Jason Merrill Cc: gcc-patches@gcc.gnu.org, Gabriel Dos Reis , Andrew Sutton , Adam Butcher Subject: [PATCH V4 2/2] Support using 'auto' in a function parameter list to introduce an implicit template parameter. Date: Tue, 10 Sep 2013 03:19:47 +0100 Message-Id: <1378779587-15362-3-git-send-email-adam@jessamine.co.uk> In-Reply-To: <1378779587-15362-1-git-send-email-adam@jessamine.co.uk> References: <1378779587-15362-1-git-send-email-adam@jessamine.co.uk> * cp-tree.h (type_uses_auto_or_concept): Declare. (is_auto_or_concept): Declare. * decl.c (grokdeclarator): Allow 'auto' parameters in lambdas with -std=gnu++1y or -std=c++1y or, as a GNU extension, in plain functions. * type-utils.h: New header defining ... (find_type_usage): ... this new function based on pt.c (type_uses_auto) for searching a type tree given a predicate. * pt.c (type_uses_auto): Reimplement via type-utils.h (find_type_usage). (is_auto_or_concept): New function. (type_uses_auto_or_concept): New function. * parser.h (struct cp_parser): Add fully_implicit_function_template_p. * parser.c (cp_parser_new): Initialize fully_implicit_function_template_p. (cp_parser_new): Initialize fully_implicit_function_template_p. (cp_parser_lambda_expression): Copy and restore value of fully_implicit_function_template_p as per other parser fields. (cp_parser_parameter_declaration_list): Count generic parameters and call ... (add_implicit_template_parms): ... this new function to synthesize them with help from type-utils.h (find_type_usage), ... (tree_type_is_auto_or_concept): ... this new static function and ... (make_generic_type_name): ... this new static function. (cp_parser_direct_declarator): Account for implicit template parameters. (cp_parser_lambda_declarator_opt): Finish fully implicit template if necessary by calling ... (finish_fully_implicit_template): ... this new function. (cp_parser_member_declaration): Likewise. (cp_parser_function_definition_after_declarator): Likewise. * Make-lang.in (cp/pt.o): Add dependency on type-utils.h. (cp/parser.o): Likewise. --- gcc/cp/Make-lang.in | 5 +- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 14 +++- gcc/cp/parser.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++-- gcc/cp/parser.h | 6 ++ gcc/cp/pt.c | 35 ++++++---- gcc/cp/type-utils.h | 55 +++++++++++++++ 7 files changed, 286 insertions(+), 26 deletions(-) create mode 100644 gcc/cp/type-utils.h diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 65dfe08..e8d4913 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -320,7 +320,7 @@ cp/except.o: cp/except.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) $(TM_P_H) cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \ toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h intl.h \ - c-family/c-objc.h + c-family/c-objc.h cp/type-utils.h cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) \ $(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \ tree-diagnostic.h tree-pretty-print.h pointer-set.h c-family/c-objc.h @@ -339,7 +339,8 @@ cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) $(REAL_H) \ gt-cp-mangle.h $(TARGET_H) $(TM_P_H) $(CGRAPH_H) cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \ gt-cp-parser.h $(TARGET_H) $(PLUGIN_H) intl.h cp/decl.h \ - c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) + c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H) \ + cp/type-utils.h cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \ $(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H) cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3e4f188..b68562d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5455,10 +5455,12 @@ extern tree make_auto (void); extern tree make_decltype_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); +extern tree type_uses_auto_or_concept (tree); extern void append_type_to_template_for_access_check (tree, tree, tree, location_t); extern tree splice_late_return_type (tree, tree); extern bool is_auto (const_tree); +extern bool is_auto_or_concept (const_tree); extern tree process_template_parm (tree, location_t, tree, bool, bool); extern tree end_template_parm_list (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b4223aa..8b67ec8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10320,8 +10320,18 @@ grokdeclarator (const cp_declarator *declarator, if (type_uses_auto (type)) { - error ("parameter declared %"); - type = error_mark_node; + if (current_class_type && LAMBDA_TYPE_P (current_class_type)) + { + if (cxx_dialect < cxx1y) + pedwarn (location_of (type), 0, + "use of % in lambda parameter declaration " + "only available with " + "-std=c++1y or -std=gnu++1y"); + } + else + pedwarn (location_of (type), OPT_Wpedantic, + "ISO C++ forbids use of % in parameter " + "declaration"); } /* A parameter declared as an array of T is really a pointer to T. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1f0c2c2..81a0bdb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "tree-pretty-print.h" #include "parser.h" +#include "type-utils.h" /* The lexer. */ @@ -2063,6 +2064,11 @@ static vec *cp_parser_initializer_list static bool cp_parser_ctor_initializer_opt_and_function_body (cp_parser *, bool); +static tree add_implicit_template_parms + (cp_parser *, size_t, tree); +static tree finish_fully_implicit_template + (cp_parser *, tree); + /* Classes [gram.class] */ static tree cp_parser_class_name @@ -3385,6 +3391,9 @@ cp_parser_new (void) /* No template parameters apply. */ parser->num_template_parameter_lists = 0; + /* Not declaring an implicit function template. */ + parser->fully_implicit_function_template_p = false; + return parser; } @@ -8549,10 +8558,12 @@ cp_parser_lambda_expression (cp_parser* parser) = parser->num_template_parameter_lists; unsigned char in_statement = parser->in_statement; bool in_switch_statement_p = parser->in_switch_statement_p; + bool fully_implicit_function_template_p = parser->fully_implicit_function_template_p; parser->num_template_parameter_lists = 0; parser->in_statement = 0; parser->in_switch_statement_p = false; + parser->fully_implicit_function_template_p = false; /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ @@ -8576,6 +8587,7 @@ cp_parser_lambda_expression (cp_parser* parser) parser->num_template_parameter_lists = saved_num_template_parameter_lists; parser->in_statement = in_statement; parser->in_switch_statement_p = in_switch_statement_p; + parser->fully_implicit_function_template_p = fully_implicit_function_template_p; } pop_deferring_access_checks (); @@ -8920,6 +8932,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) finish_template_decl (template_param_list); --parser->num_template_parameter_lists; } + else if (parser->fully_implicit_function_template_p) + fco = finish_fully_implicit_template (parser, fco); } finish_member_declaration (fco); @@ -16790,8 +16804,10 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse the parameter-declaration-clause. */ params = cp_parser_parameter_declaration_clause (parser); + /* Restore saved template parameter lists accounting for implicit + template parameters. */ parser->num_template_parameter_lists - = saved_num_template_parameter_lists; + += saved_num_template_parameter_lists; /* Consume the `)'. */ cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); @@ -17889,6 +17905,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) tree *tail = ¶meters; bool saved_in_unbraced_linkage_specification_p; int index = 0; + int implicit_template_parms = 0; /* Assume all will go well. */ *is_error = false; @@ -17916,11 +17933,18 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) deprecated_state = DEPRECATED_SUPPRESS; if (parameter) - decl = grokdeclarator (parameter->declarator, - ¶meter->decl_specifiers, - PARM, - parameter->default_argument != NULL_TREE, - ¶meter->decl_specifiers.attributes); + { + decl = grokdeclarator (parameter->declarator, + ¶meter->decl_specifiers, + PARM, + parameter->default_argument != NULL_TREE, + ¶meter->decl_specifiers.attributes); + + if (TREE_TYPE (decl) != error_mark_node + && parameter->decl_specifiers.type + && is_auto_or_concept (parameter->decl_specifiers.type)) + ++implicit_template_parms; + } deprecated_state = DEPRECATED_NORMAL; @@ -18008,6 +18032,11 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error) parser->in_unbraced_linkage_specification_p = saved_in_unbraced_linkage_specification_p; + if (parameters != error_mark_node && implicit_template_parms) + parameters = add_implicit_template_parms (parser, + implicit_template_parms, + parameters); + return parameters; } @@ -20014,7 +20043,11 @@ cp_parser_member_declaration (cp_parser* parser) attributes); /* If the member was not a friend, declare it here. */ if (!friend_p) - finish_member_declaration (decl); + { + if (parser->fully_implicit_function_template_p) + decl = finish_fully_implicit_template (parser, decl); + finish_member_declaration (decl); + } /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* If the next token is a semicolon, consume it. */ @@ -20030,6 +20063,8 @@ cp_parser_member_declaration (cp_parser* parser) initializer, /*init_const_expr_p=*/true, asm_specification, attributes); + if (parser->fully_implicit_function_template_p) + decl = finish_fully_implicit_template (parser, decl); } /* Reset PREFIX_ATTRIBUTES. */ @@ -22297,6 +22332,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, = saved_num_template_parameter_lists; parser->in_function_body = saved_in_function_body; + if (parser->fully_implicit_function_template_p) + finish_fully_implicit_template (parser, /*member_decl_opt=*/0); + return fn; } @@ -28842,4 +28880,147 @@ c_parse_file (void) the_parser = NULL; } +/* Create an identifier for a generic parameter type (a synthesized + template parameter implied by `auto' or a concept identifier). */ + +static tree +make_generic_type_name (int i) +{ + char buf[32]; + sprintf (buf, "__GenT%d", i); + return get_identifier (buf); +} + +/* Predicate that behaves as is_auto_or_concept but matches the parent + node of the generic type rather than the generic type itself. This + allows for type transformation in add_implicit_template_parms. */ + +static inline bool +tree_type_is_auto_or_concept (const_tree t) +{ + return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t)); +} + +/* Add COUNT implicit template parameters gleaned from the generic + type parameters in PARAMETERS to the CURRENT_TEMPLATE_PARMS + (creating a new template parameter list if necessary). Returns + PARAMETERS suitably rewritten to reference the newly created types + or ERROR_MARK_NODE on failure. */ + +tree +add_implicit_template_parms (cp_parser *parser, size_t count, tree parameters) +{ + gcc_assert (current_binding_level->kind == sk_function_parms); + + cp_binding_level *fn_parms_scope = current_binding_level; + + bool become_template = + fn_parms_scope->level_chain->kind != sk_template_parms; + + size_t synth_idx = 0; + + /* Roll back a scope level and either introduce a new template parameter list + or update an existing one. The function scope is added back after template + parameter synthesis below. */ + current_binding_level = fn_parms_scope->level_chain; + + /* TPARMS tracks the function's template parameter list. This is either a new + chain in the case of a fully implicit function template or an extension of + the function's explicitly specified template parameter list. */ + tree tparms = NULL_TREE; + + if (become_template) + { + push_deferring_access_checks (dk_deferred); + begin_template_parm_list (); + + parser->fully_implicit_function_template_p = true; + ++parser->num_template_parameter_lists; + } + else + { + /* Roll back the innermost template parameter list such that it may be + extended in the loop below as if it were being explicitly declared. */ + + gcc_assert (current_template_parms); + + /* Pop the innermost template parms into TPARMS. */ + tree inner_vec = INNERMOST_TEMPLATE_PARMS (current_template_parms); + current_template_parms = TREE_CHAIN (current_template_parms); + + size_t inner_vec_len = TREE_VEC_LENGTH (inner_vec); + if (inner_vec_len != 0) + { + tree t = tparms = TREE_VEC_ELT (inner_vec, 0); + for (size_t n = 1; n < inner_vec_len; ++n) + t = TREE_CHAIN (t) = TREE_VEC_ELT (inner_vec, n); + } + + ++processing_template_parmlist; + } + + for (tree p = parameters; p && synth_idx < count; p = TREE_CHAIN (p)) + { + tree generic_type_ptr + = find_type_usage (TREE_VALUE (p), tree_type_is_auto_or_concept); + + if (!generic_type_ptr) + continue; + + tree synth_id = make_generic_type_name (synth_idx++); + tree synth_tmpl_parm = finish_template_type_parm (class_type_node, + synth_id); + tparms = process_template_parm (tparms, DECL_SOURCE_LOCATION (TREE_VALUE + (p)), + build_tree_list (NULL_TREE, + synth_tmpl_parm), + /*non_type=*/false, + /*param_pack=*/false); + + /* Rewrite the type of P to be the template_parm added above (getdecls is + used to retrieve it since it is the most recent declaration in this + scope). Qualifiers need to be preserved also. */ + + tree& cur_type = TREE_TYPE (generic_type_ptr); + tree new_type = TREE_TYPE (getdecls ()); + + if (TYPE_QUALS (cur_type)) + cur_type = cp_build_qualified_type (new_type, TYPE_QUALS (cur_type)); + else + cur_type = new_type; + } + + gcc_assert (synth_idx == count); + + push_binding_level (fn_parms_scope); + + end_template_parm_list (tparms); + + return parameters; +} + +/* Finish the declaration of a fully implicit function template. Such a + template has no explicit template parameter list so has not been through the + normal template head and tail processing. add_implicit_template_parms tries + to do the head; this tries to do the tail. MEMBER_DECL_OPT should be + provided if the declaration is a class member such that its template + declaration can be completed. If MEMBER_DECL_OPT is provided the finished + form is returned. Otherwise NULL_TREE is returned. */ + +tree +finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt) +{ + gcc_assert (parser->fully_implicit_function_template_p); + + pop_deferring_access_checks (); + if (member_decl_opt) + member_decl_opt = finish_member_template_decl (member_decl_opt); + end_template_decl (); + + parser->fully_implicit_function_template_p = false; + --parser->num_template_parameter_lists; + + return member_decl_opt; +} + #include "gt-cp-parser.h" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 3d8bb74..ffdddaf 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -341,6 +341,12 @@ typedef struct GTY(()) cp_parser { /* The number of template parameter lists that apply directly to the current declaration. */ unsigned num_template_parameter_lists; + + /* TRUE if the function being declared was made a template due to its + parameter list containing generic type specifiers (`auto' or concept + identifiers) rather than an explicit template parameter list. */ + bool fully_implicit_function_template_p; + } cp_parser; /* In parser.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ba841ca..22087fb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "toplev.h" #include "timevar.h" #include "tree-iterator.h" +#include "type-utils.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ @@ -21098,31 +21099,35 @@ is_auto (const_tree type) return false; } -/* Returns true iff TYPE contains a use of 'auto'. Since auto can only - appear as a type-specifier for the declaration in question, we don't - have to look through the whole type. */ +/* Returns the TEMPLATE_TYPE_PARM in TYPE representing `auto' iff TYPE contains + a use of `auto'. Returns NULL_TREE otherwise. */ tree type_uses_auto (tree type) { - enum tree_code code; - if (is_auto (type)) - return type; + return find_type_usage (type, is_auto); +} - code = TREE_CODE (type); +/* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto', + 'decltype(auto)' or a concept. */ - if (code == POINTER_TYPE || code == REFERENCE_TYPE - || code == OFFSET_TYPE || code == FUNCTION_TYPE - || code == METHOD_TYPE || code == ARRAY_TYPE) - return type_uses_auto (TREE_TYPE (type)); +bool +is_auto_or_concept (const_tree type) +{ + return is_auto (type); // or concept +} - if (TYPE_PTRMEMFUNC_P (type)) - return type_uses_auto (TREE_TYPE (TREE_TYPE - (TYPE_PTRMEMFUNC_FN_TYPE (type)))); +/* Returns the TEMPLATE_TYPE_PARM in TYPE representing a generic type (`auto' or + a concept identifier) iff TYPE contains a use of a generic type. Returns + NULL_TREE otherwise. */ - return NULL_TREE; +tree +type_uses_auto_or_concept (tree type) +{ + return find_type_usage (type, is_auto_or_concept); } + /* For a given template T, return the vector of typedefs referenced in T for which access check is needed at T instantiation time. T is either a FUNCTION_DECL or a RECORD_TYPE. diff --git a/gcc/cp/type-utils.h b/gcc/cp/type-utils.h new file mode 100644 index 0000000..3e82ca4 --- /dev/null +++ b/gcc/cp/type-utils.h @@ -0,0 +1,55 @@ +/* Utilities for querying and manipulating type trees. + Copyright (C) 2013 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_CP_TYPE_UTILS_H +#define GCC_CP_TYPE_UTILS_H + +/* Returns the first tree within T that is directly matched by PRED. T may be a + type or PARM_DECL and is incrementally decomposed toward its type-specifier + until a match is found. NULL_TREE is returned if PRED does not match any + part of T. + + This is primarily intended for detecting whether T uses `auto' or a concept + identifier. Since either of these can only appear as a type-specifier for + the declaration in question, only top-level qualifications are traversed; + find_type_usage does not look through the whole type. */ + +inline tree +find_type_usage (tree t, bool (*pred) (const_tree)) +{ + enum tree_code code; + if (pred (t)) + return t; + + code = TREE_CODE (t); + + if (code == POINTER_TYPE || code == REFERENCE_TYPE + || code == PARM_DECL || code == OFFSET_TYPE + || code == FUNCTION_TYPE || code == METHOD_TYPE + || code == ARRAY_TYPE) + return find_type_usage (TREE_TYPE (t), pred); + + if (TYPE_PTRMEMFUNC_P (t)) + return find_type_usage + (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (t))), pred); + + return NULL_TREE; +} + +#endif // GCC_CP_TYPE_UTILS_H