From patchwork Thu Jan 20 15:40:11 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 79708 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 EC1A9B70B3 for ; Fri, 21 Jan 2011 02:40:31 +1100 (EST) Received: (qmail 3676 invoked by alias); 20 Jan 2011 15:40:27 -0000 Received: (qmail 3409 invoked by uid 22791); 20 Jan 2011 15:40:24 -0000 X-SWARE-Spam-Status: No, hits=-5.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 20 Jan 2011 15:40:16 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id p0KFeEYf012978 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 20 Jan 2011 10:40:14 -0500 Received: from adjoa.redhat.com (ovpn-113-44.phx2.redhat.com [10.3.113.44]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p0KFeBFN025380; Thu, 20 Jan 2011 10:40:13 -0500 From: Dodji Seketeli To: Jason Merrill Cc: GCC Patches Subject: PR c++/47311 X-URL: http://www.redhat.com Date: Thu, 20 Jan 2011 16:40:11 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 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 Hello, In this example: template class A; template class TC = A> class B; tsubst crashes during the fixup of the default argument T of parameter TF because it is called with a wrong argument list. The first time G++ sees template class TC, the parameters of B haven't been processed "enough" for them to appear on current_template_parms; that is, end_template_parm_list hasn't been called on them yet. So during the fixup of TF (and its default argument) as part of the parsing of 'template class TC', current_template_arg can't return any argument for {Key, T, TC}. Rather it returns {NULL, NULL, NULL}. The full argument list that is substituted into the default template argument T is then [{NULL, NULL, NULL} {TF}] while I would have naively expected it to be [{Key, T, TC} {TF}] .The index of T inside the parameters of B is 1 so it matches a NULL argument in the argument list. Hence the crash. I think we are trying to fixup the default argument of TF too early. We should wait until the point where all the parameters of B are processed to attempt a fixup of all the default arguments and non-type parameters at once. Besides, we should fixup the parameters of a given template template parameter P before fixing up the type of P itself because the parameters are needed to computed a proper canonical type for P -- I was doing the opposite. The patch below addresses these two points and has been tested on x86_64-unknown-linux-gnu against trunk. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 01f8cd7..0246948 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -192,6 +192,7 @@ static tree listify (tree); static tree listify_autos (tree, tree); static tree template_parm_to_arg (tree t); static tree current_template_args (void); +static bool incomplete_args_for_template_parm_fixup_p (tree, tree); static tree fixup_template_type_parm_type (tree, int); static tree fixup_template_parm_index (tree, tree, int); static void fixup_template_parms (void); @@ -3774,21 +3775,16 @@ fixup_template_parm (tree parm_desc, { /* PARM is a template template parameter. This is going to be interesting. */ - tree tparms, targs, innermost_args; + tree tparms, targs, innermost_args, t; int j; - /* First, fix up the type of the parm. */ + /* First, fix up the parms of the template template parm + because the parms are involved in defining the new canonical + type of the template template parm. */ - tree t = - fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); - TREE_TYPE (parm) = t; - - TREE_VEC_ELT (fixedup_args, idx) = - template_parm_to_arg (parm_desc); - - /* Now we need to substitute the template parm types that - have been fixed up so far into the non-type template - parms of this template template parm. E.g, consider this: + /* So we need to substitute the template parm types that have + been fixed up so far into the template parms of this template + template parm. E.g, consider this: template class TT> class S; @@ -3827,9 +3823,40 @@ fixup_template_parm (tree parm_desc, TREE_VEC_LENGTH (tparms), targs); } + + /* Now fix up the type of the template template parm. */ + + t = fixup_template_type_parm_type (TREE_TYPE (parm), num_parms); + TREE_TYPE (parm) = t; + + TREE_VEC_ELT (fixedup_args, idx) = + template_parm_to_arg (parm_desc); } else if (TREE_CODE (parm) == PARM_DECL) { + tree index, pushed_decl, fixed_up_index; + + if (incomplete_args_for_template_parm_fixup_p (arglist, parm)) + /* If arglist is incomplete for fixing up PARM, that might mean + PARM is a non-type parameter of a template template + parameter that we are attempting to fixup too early. E.g: + + template class A; + template class TC = A> class B; + + The first time we see the parm p, {Key, T, TC} have + obviously not been added to the current_template_parameters + yet. So the implicit ARGLIST returned by + current_template_args to substitute into p is + [{NULL,NULL,NULL}, {NULL}] instead of [{Key, T, NULL}, + {NULL}]. + + We cannot use that incomplete ARGLIST then. So let's bail + out for now, and when and Key and T have been fixed up, we + will be called again to fixup p and that time with the + complete set of implicit arguments. */ + goto end; + /* PARM is a non-type template parameter. We need to: * Fix up its TEMPLATE_PARM_INDEX to make it carry the @@ -3843,7 +3870,7 @@ fixup_template_parm (tree parm_desc, * into the type of PARM. */ - tree index = DECL_INITIAL (parm); + index = DECL_INITIAL (parm); /* PUSHED_DECL is the decl added to the symbol table with the name of the parameter. E,g: @@ -3856,12 +3883,12 @@ fixup_template_parm (tree parm_desc, PUSHED_DECL is. We need to replace the reference to the old TEMPLATE_PARM_INDEX carried by PUSHED_DECL by the fixed-up TEMPLATE_PARM_INDEX. */ - tree pushed_decl = TEMPLATE_PARM_DECL (index); - + pushed_decl = TEMPLATE_PARM_DECL (index); + /* Let's fix up the TEMPLATE_PARM_INDEX then. Note that we must fixup the type of PUSHED_DECL as well and luckily fixup_template_parm_index does it for us too. */ - tree fixed_up_index = + fixed_up_index = fixup_template_parm_index (index, arglist, num_parms); DECL_INITIAL (pushed_decl) = DECL_INITIAL (parm) = fixed_up_index; @@ -3875,14 +3902,84 @@ fixup_template_parm (tree parm_desc, tf_none, NULL_TREE); } - TREE_PURPOSE (parm_desc) = - tsubst_template_arg (TREE_PURPOSE (parm_desc), - arglist, tf_none, parm); - + /* Don't try to substitute the implicit arguments ARGLIST into the + default parameter of a template template parameter too early, + e.g: + + template < typename > class A; + template class TC = A> class B; + + The first time we see TF, we should not attempt to substitute + ARGLIST into it because ARGLIST is not complete yet. It will be + complete when all the template parameters of B are processed and + passed to end_template_parm_list to update + current_template_parms. + + It's that point that ARGLIST will be [{Key, T, NULL} {NULL}] thus + suitable to be substituted into the default argument of TF. */ + if (!incomplete_args_for_template_parm_fixup_p (arglist, + TREE_VALUE (parm_desc))) + TREE_PURPOSE (parm_desc) = + tsubst_template_arg (TREE_PURPOSE (parm_desc), + arglist, tf_none, parm); + end: pop_deferring_access_checks (); } -/* Walk current the template parms and properly compute the canonical +/* + This is a subroutine of fixup_template_parm. + + Return TRUE if the full list of template arguments [a vector of + vector as described in the comments of + TMPL_ARGS_HAVE_MULTIPLE_LEVELS] is incomplete to be used to + substitute into the template parameter PARM, for the purpose of + fixing up PARM with fixup_template_parm. ARGLIST is considered + complete if all the template levels preceding the level of PARM are + filled with arguments. Please read the comments of the places of + this function is used to understand more. */ + +static bool +incomplete_args_for_template_parm_fixup_p (tree arglist, tree parm) +{ + int i, level, index; + tree args; + + if (TREE_CODE (parm) == TYPE_DECL + || TREE_CODE (parm) == TEMPLATE_DECL) + { + level = TEMPLATE_TYPE_LEVEL (TREE_TYPE (parm)); + index = TEMPLATE_TYPE_IDX (TREE_TYPE (parm)); + } + else if (TREE_CODE (parm) == PARM_DECL) + { + level = TEMPLATE_PARM_LEVEL (DECL_INITIAL (parm)); + index = TEMPLATE_PARM_IDX (DECL_INITIAL (parm)); + } + else + return false; + + if (TMPL_ARGS_DEPTH (arglist) == 1 + && index < 1) + /* Fixing up the first template parm should always be possible + with a template arguments set of depth 1. */ + return false; + + for (i = 0; i < level - 1; ++i) + { + args = TREE_VEC_ELT (arglist, i); + gcc_assert (args != NULL_TREE); + + if (TREE_CODE (args) == TREE_VEC + && tree_vec_empty_p (args)) + return true; + } + + return false; +} + +/* Walk the current template parms and properly compute the canonical types of the dependent types created during cp_parser_template_parameter_list. */ @@ -3911,8 +4008,6 @@ fixup_template_parms (void) arglist = current_template_args (); arglist = add_outermost_template_args (arglist, fixedup_args); - fixedup_args = INNERMOST_TEMPLATE_ARGS (arglist); - /* Let's do the proper fixup now. */ for (i = 0; i < num_parms; ++i) fixup_template_parm (TREE_VEC_ELT (parameter_vec, i), diff --git a/gcc/testsuite/g++.dg/template/param2.C b/gcc/testsuite/g++.dg/template/param2.C new file mode 100644 index 0000000..d25b855 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/param2.C @@ -0,0 +1,8 @@ +// Origin PR c++/47311 +// { dg-do compile } + +template < typename > class A0; +template class TC = A0> class B0; + +template class A1; +template class TC = A1> class B1; diff --git a/gcc/tree.c b/gcc/tree.c index be2cf98..9995300 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1694,6 +1694,25 @@ make_tree_vec_stat (int len MEM_STAT_DECL) return t; } + +/* Return TRUE if T is a TREE_VEC filled with NULL_TREE or a TREE_VEC + of size zero. */ + +bool +tree_vec_empty_p (const_tree t) +{ + int i; + + if (t == NULL_TREE || TREE_CODE (t) != TREE_VEC) + return false; + + for (i = 0; i < TREE_VEC_LENGTH (t); ++i) + if (TREE_VEC_ELT (t, i) != NULL_TREE) + return false; + + return true; +} + /* Return 1 if EXPR is the integer constant zero or a complex constant of zero. */ diff --git a/gcc/tree.h b/gcc/tree.h index a49e335..a97cc20 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3988,6 +3988,8 @@ extern tree make_tree_binfo_stat (unsigned MEM_STAT_DECL); extern tree make_tree_vec_stat (int MEM_STAT_DECL); #define make_tree_vec(t) make_tree_vec_stat (t MEM_STAT_INFO) +bool tree_vec_empty_p (const_tree t); + /* Return the (unique) IDENTIFIER_NODE node for a given name. The name is supplied as a char *. */