From patchwork Tue May 1 12:00:16 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 156051 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]) by ozlabs.org (Postfix) with SMTP id 8FB39B6FA5 for ; Tue, 1 May 2012 22:01:07 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1336478469; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Message-ID:Date:From:User-Agent:MIME-Version: To:CC:Subject:References:In-Reply-To:Content-Type:Mailing-List: Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:Sender:Delivered-To; bh=7a95QuPSEqq28s9+nZRLWeWTU+k=; b=cbYPQm/SxZjy3mVlrEJ3UHYKojblPXawKNnZpT9F6pMaSpXRRoo+UBmwH/By69 6gkyQMk2u7cwaUbwLjOHPbP3eVgsNd0aEZ8xjY9BO01+GuEeUmHckxAyzOIImCsm UeOUH8ZYUBj2Dp+GBoJhCbPFwRQyan8bxeWB0HtSR0tzg= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=rLFekJYx6UPCHFZbBVOTWcvvqc/qIqtMHmCHt9TS5N8dpiP3QzxDegya11P1CL HmVNMVy3CKteTO9TiSN4yhd4dUzvFTfcTtJ2SPKZf9imYxFSqZBewDWsPeK4M8b0 nW92M03pAwVlpPQbIOlqS0Mcq/MaE+IP8vBWkhWBOacw4=; Received: (qmail 11154 invoked by alias); 1 May 2012 12:01:03 -0000 Received: (qmail 11135 invoked by uid 22791); 1 May 2012 12:01:00 -0000 X-SWARE-Spam-Status: No, hits=-7.1 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_THREADED, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_NO, RCVD_IN_HOSTKARMA_W, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from acsinet15.oracle.com (HELO acsinet15.oracle.com) (141.146.126.227) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 01 May 2012 12:00:46 +0000 Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by acsinet15.oracle.com (Sentrion-MTA-4.2.2/Sentrion-MTA-4.2.2) with ESMTP id q41C0h5F031908 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 1 May 2012 12:00:44 GMT Received: from acsmt358.oracle.com (acsmt358.oracle.com [141.146.40.158]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id q41C0hcA017021 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 1 May 2012 12:00:43 GMT Received: from abhmt119.oracle.com (abhmt119.oracle.com [141.146.116.71]) by acsmt358.oracle.com (8.12.11.20060308/8.12.11) with ESMTP id q41C0g8U013413; Tue, 1 May 2012 07:00:42 -0500 Received: from [192.168.1.4] (/79.52.234.239) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 01 May 2012 05:00:41 -0700 Message-ID: <4F9FD050.7040700@oracle.com> Date: Tue, 01 May 2012 14:00:16 +0200 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20120421 Thunderbird/12.0 MIME-Version: 1.0 To: Jason Merrill CC: "gcc-patches@gcc.gnu.org" Subject: Re: [RFH / Patch] PR 51222 References: <4F9B4B10.7090409@oracle.com> <4F9B62F0.5090202@redhat.com> <4F9BD0B8.4030005@oracle.com> <4F9CB2C9.3060700@redhat.com> <4F9D6180.4030408@oracle.com> <4F9EC605.2050703@redhat.com> <4F9F2243.7000802@oracle.com> <4F9F665D.2090806@redhat.com> In-Reply-To: <4F9F665D.2090806@redhat.com> X-IsSubscribed: yes 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 On 05/01/2012 06:28 AM, Jason Merrill wrote: > On 04/30/2012 07:37 PM, Paolo Carlini wrote: >> Thus, my question would be: is something like the below in the right >> direction? The alternate possibility I can see, would be basically >> redoing a slightly slimmed version of for_each_template_parm specialized >> for our needs (a few less conditionals) > I think either approach would be fine; I lean toward the first, but > changing the name and adding a flag for clarity. Changing the walking > behavior based on fn being null is too subtle. Agreed. The below is what I booted and tested on x86_64-linux. Thanks, Paolo. /////////////////// /cp 2012-05-01 Paolo Carlini PR c++/51222 * pt.c (for_each_template_parm): Rename to walk_template_parms, add any_p bool parameter. (mark_template_parm, uses_template_parms_level): Adjust. (instantiation_dependent_expression_p): New. (finish_decltype_type): Use it. * cp-tree.h: Update declarations. /testsuite 2012-05-01 Paolo Carlini PR c++/51222 * g++.dg/cpp0x/decltype37.C: New. Index: testsuite/g++.dg/cpp0x/decltype37.C =================================================================== --- testsuite/g++.dg/cpp0x/decltype37.C (revision 0) +++ testsuite/g++.dg/cpp0x/decltype37.C (revision 0) @@ -0,0 +1,101 @@ +// PR c++/51222 +// { dg-options -std=c++11 } + +template +struct add_rref { + typedef T&& type; +}; + +template<> +struct add_rref { + typedef void type; +}; + +template +typename add_rref::type declval(); + +template())) +> +auto f(int) -> char; + +template +auto f(...) -> char(&)[2]; + +template +auto g(int) -> char; + +template +auto g(...) -> char(&)[2]; + +template +auto f2(int) -> decltype(::delete ::new T(declval()), char()); + +template +auto f2(...) -> char(&)[2]; + +template +auto g2(int) -> decltype(::delete ::new T(), char()); + +template +auto g2(...) -> char(&)[2]; + +struct C { }; + +struct A { + virtual ~A() = 0; +}; + +struct D1 { + D1() = delete; +}; + +struct D2 { + ~D2() = delete; +}; + +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(g(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); +static_assert(sizeof(f(0)) == 2, "Ouch"); + +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(g2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); +static_assert(sizeof(f2(0)) == 2, "Ouch"); Index: cp/pt.c =================================================================== --- cp/pt.c (revision 187012) +++ cp/pt.c (working copy) @@ -145,8 +145,8 @@ static tree convert_nontype_argument_function (tre static tree convert_nontype_argument (tree, tree, tsubst_flags_t); static tree convert_template_argument (tree, tree, tree, tsubst_flags_t, int, tree); -static int for_each_template_parm (tree, tree_fn_t, void*, - struct pointer_set_t*, bool); +static int walk_template_parms (tree, tree_fn_t, void*, + struct pointer_set_t*, bool, bool); static tree expand_template_argument_pack (tree); static tree build_template_parm_index (int, int, int, int, tree, tree); static bool inline_needs_template_parms (tree); @@ -185,7 +185,7 @@ static int coerce_template_template_parms (tree, t static bool template_template_parm_bindings_ok_p (tree, tree); static int template_args_equal (tree, tree); static void tsubst_default_arguments (tree); -static tree for_each_template_parm_r (tree *, int *, void *); +static tree walk_template_parms_r (tree *, int *, void *); static tree copy_default_args_to_explicit_spec_1 (tree, tree); static void copy_default_args_to_explicit_spec (tree); static int invalid_nontype_parm_type_p (tree, tsubst_flags_t); @@ -4276,8 +4276,8 @@ mark_template_parm (tree t, void* data) tpd->arg_uses_template_parms[tpd->current_arg] = 1; } - /* Return zero so that for_each_template_parm will continue the - traversal of the tree; we want to mark *every* template parm. */ + /* Return zero so that walk_template_parms will continue the traversal + of the tree; we want to mark *every* template parm. */ return 0; } @@ -4344,11 +4344,12 @@ process_partial_specialization (tree decl) for (i = 0; i < nargs; ++i) { tpd.current_arg = i; - for_each_template_parm (TREE_VEC_ELT (inner_args, i), - &mark_template_parm, - &tpd, - NULL, - /*include_nondeduced_p=*/false); + walk_template_parms (TREE_VEC_ELT (inner_args, i), + &mark_template_parm, + &tpd, + NULL, + /*any_p=*/false, + /*include_nondeduced_p=*/false); } for (i = 0; i < ntparms; ++i) if (tpd.parms[i] == 0) @@ -4481,11 +4482,12 @@ process_partial_specialization (tree decl) tpd2.current_arg = i; tpd2.arg_uses_template_parms[i] = 0; memset (tpd2.parms, 0, sizeof (int) * nargs); - for_each_template_parm (type, - &mark_template_parm, - &tpd2, - NULL, - /*include_nondeduced_p=*/false); + walk_template_parms (type, + &mark_template_parm, + &tpd2, + NULL, + /*any_p=*/false, + /*include_nondeduced_p=*/false); if (tpd2.arg_uses_template_parms [i]) { @@ -4755,7 +4757,7 @@ check_default_tmpl_args (tree decl, tree parms, in } /* Worker for push_template_decl_real, called via - for_each_template_parm. DATA is really an int, indicating the + walk_template_parms. DATA is really an int, indicating the level of the parameters we are interested in. If T is a template parameter of that level, return nonzero. */ @@ -7750,16 +7752,17 @@ struct pair_fn_data { tree_fn_t fn; void *data; + bool any_p; /* True when we should also visit template parameters that occur in non-deduced contexts. */ bool include_nondeduced_p; struct pointer_set_t *visited; }; -/* Called from for_each_template_parm via walk_tree. */ +/* Called from walk_template_parms via walk_tree. */ static tree -for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) +walk_template_parms_r (tree *tp, int *walk_subtrees, void *d) { tree t = *tp; struct pair_fn_data *pfd = (struct pair_fn_data *) d; @@ -7768,8 +7771,9 @@ static tree if (TYPE_P (t) && (pfd->include_nondeduced_p || TREE_CODE (t) != TYPENAME_TYPE) - && for_each_template_parm (TYPE_CONTEXT (t), fn, data, pfd->visited, - pfd->include_nondeduced_p)) + && walk_template_parms (TYPE_CONTEXT (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; switch (TREE_CODE (t)) @@ -7783,34 +7787,39 @@ static tree case ENUMERAL_TYPE: if (!TYPE_TEMPLATE_INFO (t)) *walk_subtrees = 0; - else if (for_each_template_parm (TI_ARGS (TYPE_TEMPLATE_INFO (t)), - fn, data, pfd->visited, - pfd->include_nondeduced_p)) + else if (walk_template_parms (TI_ARGS (TYPE_TEMPLATE_INFO (t)), + fn, data, pfd->visited, + pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; break; case INTEGER_TYPE: - if (for_each_template_parm (TYPE_MIN_VALUE (t), - fn, data, pfd->visited, - pfd->include_nondeduced_p) - || for_each_template_parm (TYPE_MAX_VALUE (t), - fn, data, pfd->visited, - pfd->include_nondeduced_p)) + if (walk_template_parms (TYPE_MIN_VALUE (t), + fn, data, pfd->visited, + pfd->any_p, + pfd->include_nondeduced_p) + || walk_template_parms (TYPE_MAX_VALUE (t), + fn, data, pfd->visited, + pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; break; case METHOD_TYPE: /* Since we're not going to walk subtrees, we have to do this explicitly here. */ - if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + if (walk_template_parms (TYPE_METHOD_BASETYPE (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Fall through. */ case FUNCTION_TYPE: /* Check the return type. */ - if (for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited, - pfd->include_nondeduced_p)) + if (walk_template_parms (TREE_TYPE (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Check the parameter types. Since default arguments are not @@ -7823,8 +7832,9 @@ static tree tree parm; for (parm = TYPE_ARG_TYPES (t); parm; parm = TREE_CHAIN (parm)) - if (for_each_template_parm (TREE_VALUE (parm), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + if (walk_template_parms (TREE_VALUE (parm), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Since we've already handled the TYPE_ARG_TYPES, we don't @@ -7836,37 +7846,46 @@ static tree case TYPEOF_TYPE: case UNDERLYING_TYPE: if (pfd->include_nondeduced_p - && for_each_template_parm (TYPE_FIELDS (t), fn, data, - pfd->visited, - pfd->include_nondeduced_p)) + && walk_template_parms (TYPE_FIELDS (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; break; case FUNCTION_DECL: case VAR_DECL: if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t) - && for_each_template_parm (DECL_TI_ARGS (t), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + && walk_template_parms (DECL_TI_ARGS (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Fall through. */ case PARM_DECL: case CONST_DECL: if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t) - && for_each_template_parm (DECL_INITIAL (t), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + && walk_template_parms (DECL_INITIAL (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; if (DECL_CONTEXT (t) && pfd->include_nondeduced_p - && for_each_template_parm (DECL_CONTEXT (t), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + && walk_template_parms (DECL_CONTEXT (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; + if (pfd->any_p && TREE_TYPE (t) + && walk_template_parms (TREE_TYPE(t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) + return error_mark_node; break; case BOUND_TEMPLATE_TEMPLATE_PARM: /* Record template parameters such as `T' inside `TT'. */ - if (for_each_template_parm (TYPE_TI_ARGS (t), fn, data, pfd->visited, - pfd->include_nondeduced_p)) + if (walk_template_parms (TYPE_TI_ARGS (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Fall through. */ @@ -7882,8 +7901,9 @@ static tree case TEMPLATE_DECL: /* A template template parameter is encountered. */ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t) - && for_each_template_parm (TREE_TYPE (t), fn, data, pfd->visited, - pfd->include_nondeduced_p)) + && walk_template_parms (TREE_TYPE (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; /* Already substituted template template parameter */ @@ -7892,19 +7912,25 @@ static tree case TYPENAME_TYPE: if (!fn - || for_each_template_parm (TYPENAME_TYPE_FULLNAME (t), fn, - data, pfd->visited, - pfd->include_nondeduced_p)) + || walk_template_parms (TYPENAME_TYPE_FULLNAME (t), fn, + data, pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; break; case CONSTRUCTOR: if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)) && pfd->include_nondeduced_p - && for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE - (TREE_TYPE (t)), fn, data, - pfd->visited, pfd->include_nondeduced_p)) + && walk_template_parms (TYPE_PTRMEMFUNC_FN_TYPE + (TREE_TYPE (t)), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) return error_mark_node; + else if (pfd->any_p && TREE_TYPE (t) + && walk_template_parms (TREE_TYPE (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) + return error_mark_node; break; case INDIRECT_REF: @@ -7913,6 +7939,11 @@ static tree involving template parameters. */ if (!fn && !TREE_TYPE (t)) return error_mark_node; + else if (pfd->any_p && TREE_TYPE (t) + && walk_template_parms (TREE_TYPE (t), fn, data, + pfd->visited, pfd->any_p, + pfd->include_nondeduced_p)) + return error_mark_node; break; case MODOP_EXPR: @@ -7938,35 +7969,41 @@ static tree return NULL_TREE; } -/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, - BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX in T, - call FN with the parameter and the DATA. - If FN returns nonzero, the iteration is terminated, and - for_each_template_parm returns 1. Otherwise, the iteration - continues. If FN never returns a nonzero value, the value - returned by for_each_template_parm is 0. If FN is NULL, it is - considered to be the function which always returns 1. +/* Walk T looking for TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, + BOUND_TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX. + If ANY_P is true, return 1 if any, 0 otherwise. + + If ANY_P is false, for each the iteration calls FN with the parameter + and the DATA. If FN returns nonzero, the iteration is terminated, + and walk_template_parms returns 1. Otherwise, the iteration continues. + If FN never returns a nonzero value, the value returned by + walk_template_parms is 0. If FN is NULL, it is considered to be the + function which always returns 1. + If INCLUDE_NONDEDUCED_P, then this routine will also visit template parameters that occur in non-deduced contexts. When false, only visits those template parameters that can be deduced. */ static int -for_each_template_parm (tree t, tree_fn_t fn, void* data, - struct pointer_set_t *visited, - bool include_nondeduced_p) +walk_template_parms (tree t, tree_fn_t fn, void* data, + struct pointer_set_t *visited, + bool any_p, bool include_nondeduced_p) { struct pair_fn_data pfd; int result; /* Set up. */ - pfd.fn = fn; + /* When any_p is true, fn plays no role, thus make sure is NULL, + which simplifies a bit walk_template_parms_r. */ + pfd.fn = any_p ? NULL : fn; pfd.data = data; + pfd.any_p = any_p; pfd.include_nondeduced_p = include_nondeduced_p; /* Walk the tree. (Conceptually, we would like to walk without - duplicates, but for_each_template_parm_r recursively calls - for_each_template_parm, so we would need to reorganize a fair + duplicates, but walk_template_parms_r recursively calls + walk_template_parms, so we would need to reorganize a fair bit to use walk_tree_without_duplicates, so we keep our own visited list.) */ if (visited) @@ -7974,7 +8011,7 @@ static int else pfd.visited = pointer_set_create (); result = cp_walk_tree (&t, - for_each_template_parm_r, + walk_template_parms_r, &pfd, pfd.visited) != NULL_TREE; @@ -8035,8 +8072,9 @@ uses_template_parms (tree t) int uses_template_parms_level (tree t, int level) { - return for_each_template_parm (t, template_parm_this_level_p, &level, NULL, - /*include_nondeduced_p=*/true); + return walk_template_parms (t, template_parm_this_level_p, &level, NULL, + /*any_p=*/false, + /*include_nondeduced_p=*/true); } /* Returns TRUE iff INST is an instantiation we don't need to do in an @@ -19744,6 +19782,30 @@ type_dependent_expression_p (tree expression) return (dependent_type_p (TREE_TYPE (expression))); } +/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the + sense defined by the ABI: + + "An expression is instantiation-dependent if it is type-dependent + or value-dependent, or it has a subexpression that is type-dependent + or value-dependent." */ + +bool +instantiation_dependent_expression_p (tree expression) +{ + if (!processing_template_decl) + return false; + + if (expression == error_mark_node) + return false; + + if (!TREE_TYPE (expression)) + return true; + + return walk_template_parms (expression, /*fn=*/NULL, NULL, NULL, + /*any_p=*/true, + /*include_nondeduced_p=*/true); +} + /* Like type_dependent_expression_p, but it also works while not processing a template definition, i.e. during substitution or mangling. */ Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 187012) +++ cp/semantics.c (working copy) @@ -5168,8 +5168,7 @@ finish_decltype_type (tree expr, bool id_expressio return error_mark_node; } - /* FIXME instantiation-dependent */ - if (type_dependent_expression_p (expr) + if (instantiation_dependent_expression_p (expr) /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even if it isn't dependent, so that we can check access control at instantiation time, so defer the decltype as well (PR 42277). */ Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 187012) +++ cp/cp-tree.h (working copy) @@ -5363,6 +5363,7 @@ extern bool any_type_dependent_arguments_p (c extern bool any_type_dependent_elements_p (const_tree); extern bool type_dependent_expression_p_push (tree); extern bool value_dependent_expression_p (tree); +extern bool instantiation_dependent_expression_p(tree); extern bool any_value_dependent_elements_p (const_tree); extern bool dependent_omp_for_p (tree, tree, tree, tree); extern tree resolve_typename_type (tree, bool);