From patchwork Fri Feb 20 19:59:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harald van Dijk X-Patchwork-Id: 442138 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.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D999714017C for ; Sat, 21 Feb 2015 06:59:33 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=ZIkAG36bB4rKpJ5Q047I8MNsdQDVHILuQKIVxAhQ+nhSmH QtJHyh5d+1v6lOouYZ5mp2lMtVCsPulJAvFkdI7+sGBXMzEopvGBm9Gr5Gk/6sBQ Ux9DB8baR4ElZZA3MdNrjKBa8apRQx3BhmssJ/YuhbL9lMdVWmFC6PAEr0r2I= 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 :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=ymmsTyu5DMRbCN2Q/mgF6wWonIw=; b=ieKs2UwLCuRs8lbCHfYH Hy81seF0QtOMTFgh/Lbgoa+ANlDYPH7IztmBizbQnUebrOU3VEuTJaHSUMVc2EVP m8VTOeRIZav0/DpicIk4iM0Q+rCxlacD4cBLwr6Mp8fJOEnaSSJVHax2X39cSKrb 3egMB90tUFjVX+Yd61jKBFo= Received: (qmail 4425 invoked by alias); 20 Feb 2015 19:59:25 -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 4415 invoked by uid 89); 20 Feb 2015 19:59:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham version=3.3.2 X-HELO: hosting12.csv-networks.nl Received: from hosting12.csv-networks.nl (HELO hosting12.csv-networks.nl) (84.244.151.217) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Fri, 20 Feb 2015 19:59:22 +0000 Received: from home.gigawatt.nl ([83.163.3.213] helo=[192.168.178.26]) by hosting12.csv-networks.nl with esmtpsa (TLSv1:DHE-RSA-AES128-SHA:128) (Exim 4.80) (envelope-from ) id 1YOtjI-0002V0-E1 for gcc-patches@gcc.gnu.org; Fri, 20 Feb 2015 20:59:16 +0100 Message-ID: <54E79213.7060809@gigawatt.nl> Date: Fri, 20 Feb 2015 20:59:15 +0100 From: Harald van Dijk User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org Subject: [PATCH, RFC] Make generic functions work with 'auto' return types (PR64969) Hello all, As noted in the bug, and a couple of times on StackOverflow, generic functions and 'auto' return types do not play nice together. This happens because the parser does not expect a level of template parameters to be added to a function after it has already parsed 'auto' in a return type. To make it work requires either patching up existing references to 'auto' after that additional level of template parameters gets added, or change the representation of 'auto' to something that does not depend on the level of template parameters. The latter seemed easiest: a fixed level of 0 (otherwise unused) works well. The added test used to fail, passes with this patch, and there's no other change in test results (--enable-languages=c,c++). Does this approach look correct? Does the patch itself look correct? Is fixing this appropriate for GCC 5.0? It's not a regression, it fails on 4.9 (the first version that added support for generic functions) too. I'm happy to wait until after 5.0 is released. Note: I don't have any copyright assignment, and getting that may be troublesome right now. However, a copyright disclaimer for this change should not be a problem. Who should I contact about that? Cheers, Harald van Dijk gcc/cp/ PR 64969 * cp-tree.h (tsubst_flags): Add tf_auto. * pt.c (make_auto_1): Encode auto with a level of 0. (tsubst): Change auto to its proper level. Ignore unless tf_auto. (tsubst_pack_expansion): Add sanity check. (reduce_template_parm_level): Ignore auto. (listify_autos): Pass tf_auto. (do_auto_deduction): Likewise. (splice_late_return_type): Likewise. gcc/testsuite/ PR 64969 * g++.dg/cpp1y/pr64969.C: New test. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 65219f1..575cb4d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4427,6 +4427,7 @@ enum tsubst_flags { for calls in decltype (5.2.2/11). */ tf_partial = 1 << 8, /* Doing initial explicit argument substitution in fn_type_unification. */ + tf_auto = 1 << 9, /* Substitute auto. */ /* Convenient substitution flags combinations. */ tf_warning_or_error = tf_warning | tf_error }; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9a00d0d..0221d48 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3699,8 +3699,10 @@ reduce_template_parm_level (tree index, tree type, int levels, tree args, DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); - t = build_template_parm_index (TEMPLATE_PARM_IDX (index), - TEMPLATE_PARM_LEVEL (index) - levels, + int level = TEMPLATE_PARM_LEVEL (index); + if (level) + level -= levels; + t = build_template_parm_index (TEMPLATE_PARM_IDX (index), level, TEMPLATE_PARM_ORIG_LEVEL (index), decl, type); TEMPLATE_PARM_DESCENDANTS (index) = t; @@ -10003,6 +10005,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, int idx; template_parm_level_and_index (parm_pack, &level, &idx); + /* A pack can never be 'auto'. */ + gcc_assert (level); + if (level <= levels) arg_pack = TMPL_ARG (args, level, idx); } @@ -11968,8 +11973,16 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) gcc_assert (TREE_VEC_LENGTH (args) > 0); template_parm_level_and_index (t, &level, &idx); + /* A level of zero represents 'auto'. If complain & tf_auto, + then the template arguments will contain a deduced or + specified type for auto at one level deeper than the current + template parameters. The value of processing_template_decl + is not meaningful here in other cases. */ + if (complain & tf_auto && !level) + level = processing_template_decl + 1; + levels = TMPL_ARGS_DEPTH (args); - if (level <= levels) + if (level && level <= levels) { arg = TMPL_ARG (args, level, idx); @@ -22095,8 +22108,7 @@ make_args_non_dependent (vec *args) } /* Returns a type which represents 'auto' or 'decltype(auto)'. We use a - TEMPLATE_TYPE_PARM with a level one deeper than the actual template - parms. */ + TEMPLATE_TYPE_PARM with a level of 0. */ static tree make_auto_1 (tree name) @@ -22106,8 +22118,7 @@ make_auto_1 (tree name) TYPE_DECL, name, au); TYPE_STUB_DECL (au) = TYPE_NAME (au); TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index - (0, processing_template_decl + 1, processing_template_decl + 1, - TYPE_NAME (au), NULL_TREE); + (0, 0, 0, TYPE_NAME (au), NULL_TREE); TYPE_CANONICAL (au) = canonical_type_parameter (au); DECL_ARTIFICIAL (TYPE_NAME (au)) = 1; SET_DECL_TEMPLATE_PARM_P (TYPE_NAME (au)); @@ -22157,7 +22168,7 @@ listify_autos (tree type, tree auto_node) TREE_VEC_ELT (argvec, 0) = init_auto; if (processing_template_decl) argvec = add_to_template_args (current_template_args (), argvec); - return tsubst (type, argvec, tf_warning_or_error, NULL_TREE); + return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE); } /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced @@ -22264,7 +22275,7 @@ do_auto_deduction (tree type, tree init, tree auto_node) if (processing_template_decl) targs = add_to_template_args (current_template_args (), targs); - return tsubst (type, targs, tf_warning_or_error, NULL_TREE); + return tsubst (type, targs, tf_warning_or_error | tf_auto, NULL_TREE); } /* Substitutes LATE_RETURN_TYPE for 'auto' in TYPE and returns the @@ -22286,7 +22297,7 @@ splice_late_return_type (tree type, tree late_return_type) (make_tree_vec (processing_template_parmlist), argvec); if (current_template_parms) argvec = add_to_template_args (current_template_args (), argvec); - return tsubst (type, argvec, tf_warning_or_error, NULL_TREE); + return tsubst (type, argvec, tf_warning_or_error | tf_auto, NULL_TREE); } /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto' or diff --git a/gcc/testsuite/g++.dg/cpp1y/pr64969.C b/gcc/testsuite/g++.dg/cpp1y/pr64969.C new file mode 100644 index 0000000..05848b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr64969.C @@ -0,0 +1,23 @@ +// { dg-do compile { target c++14 } } +// { dg-options "" } + +int f(); + +auto t1(auto f) +{ return f(); } + +decltype(auto) t2(auto f) +{ return f(); } + +template +auto t3(auto f) +{ return f(); } + +template +decltype(auto) t4(auto f) +{ return f(); } + +int r1 = t1(f); +int r2 = t2(f); +int r3 = t3(f) | t3(f); +int r4 = t4(f) | t4(f);