From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id B821E3855009; Fri, 11 Jun 2021 20:09:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B821E3855009 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-1398] c++: Substitute into function parms in lexical order [PR96560] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 1e690757d30775ed340a368b9a9463b2ad68de01 X-Git-Newrev: b0d73a66ae3962fa83309527d85613d72a6aa43d Message-Id: <20210611200954.B821E3855009@sourceware.org> Date: Fri, 11 Jun 2021 20:09:54 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Jun 2021 20:09:54 -0000 https://gcc.gnu.org/g:b0d73a66ae3962fa83309527d85613d72a6aa43d commit r12-1398-gb0d73a66ae3962fa83309527d85613d72a6aa43d Author: Patrick Palka Date: Fri Jun 11 16:00:52 2021 -0400 c++: Substitute into function parms in lexical order [PR96560] This makes tsubst_arg_types substitute into a function's parameter types in left-to-right instead of right-to-left order, in accordance with DR 1227. DR 1227 PR c++/96560 gcc/cp/ChangeLog: * pt.c (tsubst_arg_types): Rearrange so that we substitute into TYPE_ARG_TYPES in forward order while short circuiting appropriately. Adjust formatting. gcc/testsuite/ChangeLog: * g++.dg/template/sfinae-dr1227.C: New test. Diff: --- gcc/cp/pt.c | 115 ++++++++++++++------------ gcc/testsuite/g++.dg/template/sfinae-dr1227.C | 23 ++++++ 2 files changed, 83 insertions(+), 55 deletions(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b53df9e2ad6..141388ad2e5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14946,20 +14946,13 @@ tsubst_arg_types (tree arg_types, tsubst_flags_t complain, tree in_decl) { - tree remaining_arg_types; tree type = NULL_TREE; - int i = 1; + int len = 1; tree expanded_args = NULL_TREE; - tree default_arg; if (!arg_types || arg_types == void_list_node || arg_types == end) return arg_types; - remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types), - args, end, complain, in_decl); - if (remaining_arg_types == error_mark_node) - return error_mark_node; - if (PACK_EXPANSION_P (TREE_VALUE (arg_types))) { /* For a pack expansion, perform substitution on the @@ -14970,7 +14963,7 @@ tsubst_arg_types (tree arg_types, if (TREE_CODE (expanded_args) == TREE_VEC) /* So that we'll spin through the parameters, one by one. */ - i = TREE_VEC_LENGTH (expanded_args); + len = TREE_VEC_LENGTH (expanded_args); else { /* We only partially substituted into the parameter @@ -14979,59 +14972,71 @@ tsubst_arg_types (tree arg_types, expanded_args = NULL_TREE; } } + else + type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl); - while (i > 0) { - --i; - - if (expanded_args) - type = TREE_VEC_ELT (expanded_args, i); - else if (!type) - type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl); + /* Check if a substituted type is erroneous before substituting into + the rest of the chain. */ + for (int i = 0; i < len; i++) + { + if (expanded_args) + type = TREE_VEC_ELT (expanded_args, i); - if (type == error_mark_node) - return error_mark_node; - if (VOID_TYPE_P (type)) - { - if (complain & tf_error) - { - error ("invalid parameter type %qT", type); - if (in_decl) - error ("in declaration %q+D", in_decl); - } - return error_mark_node; + if (type == error_mark_node) + return error_mark_node; + if (VOID_TYPE_P (type)) + { + if (complain & tf_error) + { + error ("invalid parameter type %qT", type); + if (in_decl) + error ("in declaration %q+D", in_decl); + } + return error_mark_node; + } } - /* Do array-to-pointer, function-to-pointer conversion, and ignore - top-level qualifiers as required. */ - type = cv_unqualified (type_decays_to (type)); + /* We do not substitute into default arguments here. The standard + mandates that they be instantiated only when needed, which is + done in build_over_call. */ + tree default_arg = TREE_PURPOSE (arg_types); - /* We do not substitute into default arguments here. The standard - mandates that they be instantiated only when needed, which is - done in build_over_call. */ - default_arg = TREE_PURPOSE (arg_types); + /* Except that we do substitute default arguments under tsubst_lambda_expr, + since the new op() won't have any associated template arguments for us + to refer to later. */ + if (lambda_fn_in_template_p (in_decl)) + default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl, + false/*fn*/, false/*constexpr*/); - /* Except that we do substitute default arguments under tsubst_lambda_expr, - since the new op() won't have any associated template arguments for us - to refer to later. */ - if (lambda_fn_in_template_p (in_decl)) - default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl, - false/*fn*/, false/*constexpr*/); + tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types), + args, end, complain, in_decl); + if (remaining_arg_types == error_mark_node) + return error_mark_node; - if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE) - { - /* We've instantiated a template before its default arguments - have been parsed. This can happen for a nested template - class, and is not an error unless we require the default - argument in a call of this function. */ - remaining_arg_types = - tree_cons (default_arg, type, remaining_arg_types); - vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg), - remaining_arg_types); - } - else - remaining_arg_types = - hash_tree_cons (default_arg, type, remaining_arg_types); - } + for (int i = len-1; i >= 0; i--) + { + if (expanded_args) + type = TREE_VEC_ELT (expanded_args, i); + + /* Do array-to-pointer, function-to-pointer conversion, and ignore + top-level qualifiers as required. */ + type = cv_unqualified (type_decays_to (type)); + + if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE) + { + /* We've instantiated a template before its default arguments + have been parsed. This can happen for a nested template + class, and is not an error unless we require the default + argument in a call of this function. */ + remaining_arg_types + = tree_cons (default_arg, type, remaining_arg_types); + vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg), + remaining_arg_types); + } + else + remaining_arg_types + = hash_tree_cons (default_arg, type, remaining_arg_types); + } return remaining_arg_types; } diff --git a/gcc/testsuite/g++.dg/template/sfinae-dr1227.C b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C new file mode 100644 index 00000000000..821ff0313b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sfinae-dr1227.C @@ -0,0 +1,23 @@ +// PR c++/96560 +// DR 1227 +// Test that we substitute function parameter types in lexical order. + +template +struct A { typedef typename T::type type; }; // { dg-error "void" } + +template void f(typename T::type, typename A::type); +template long f(...); + +long x = f(0, 0); // { dg-bogus "" } OK + + +template void g(T, typename A::type); +template long g(...); + +long y = g(0, 0); // { dg-bogus "" } OK + + +template void h(typename A::type, T); +template long h(...); + +long z = h(0, 0); // { dg-message "required from here" } hard error