From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 0C6AF3858403; Mon, 30 Aug 2021 21:23:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0C6AF3858403 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jason Merrill To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-3234] c++: fold function template args sooner [PR101460] X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/heads/master X-Git-Oldrev: a7083b83e45852540a4a09ee11b74dc28d777399 X-Git-Newrev: a8de832470f78a40a0e2c8de866a471bf74bf0ab Message-Id: <20210830212338.0C6AF3858403@sourceware.org> Date: Mon, 30 Aug 2021 21:23:38 +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: Mon, 30 Aug 2021 21:23:38 -0000 https://gcc.gnu.org/g:a8de832470f78a40a0e2c8de866a471bf74bf0ab commit r12-3234-ga8de832470f78a40a0e2c8de866a471bf74bf0ab Author: Jason Merrill Date: Mon Aug 30 09:44:28 2021 -0400 c++: fold function template args sooner [PR101460] As discussed in the PR, we were giving a lot of unnecessary errors for this testcase because we didn't try to do constant evaluation until convert_nontype_argument, which happens for each of the candidates. But when looking at a template-id as the function operand of a call, we can try to fold arguments before we get into overload resolution. PR c++/101460 gcc/cp/ChangeLog: * cp-tree.h (cxx_constant_value_sfinae): Declare. * constexpr.c (cxx_constant_value_sfinae): New. * pt.c (fold_targs_r, maybe_fold_fn_template_args): New. (tsubst_copy_and_build) [CALL_EXPR]: Call maybe_fold_fn_template_args. gcc/testsuite/ChangeLog: * g++.dg/template/explicit-args6.C: New test. Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/constexpr.c | 12 ++++++ gcc/cp/pt.c | 60 ++++++++++++++++++++++++++ gcc/testsuite/g++.dg/template/explicit-args6.C | 34 +++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 75ee88721b4..6a179375a56 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8266,6 +8266,7 @@ extern bool require_constant_expression (tree); extern bool require_rvalue_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree); extern tree cxx_constant_value (tree, tree = NULL_TREE); +extern tree cxx_constant_value_sfinae (tree, tsubst_flags_t); extern void cxx_constant_dtor (tree, tree); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE, bool = false); diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b9c006217be..9606719bc73 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -7458,6 +7458,18 @@ cxx_constant_value (tree t, tree decl) return cxx_eval_outermost_constant_expr (t, false, true, true, false, decl); } +/* As above, but respect SFINAE. */ + +tree +cxx_constant_value_sfinae (tree t, tsubst_flags_t complain) +{ + bool sfinae = !(complain & tf_error); + tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true); + if (sfinae && !TREE_CONSTANT (r)) + r = error_mark_node; + return r; +} + /* Like cxx_constant_value, but used for evaluation of constexpr destructors of constexpr variables. The actual initializer of DECL is not modified. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 020a4bf2f6d..d7d0dce691c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19465,6 +19465,63 @@ out: return r; } +/* Subroutine of maybe_fold_fn_template_args. */ + +static bool +fold_targs_r (tree targs, tsubst_flags_t complain) +{ + int len = TREE_VEC_LENGTH (targs); + for (int i = 0; i < len; ++i) + { + tree &elt = TREE_VEC_ELT (targs, i); + if (!elt || TYPE_P (elt) + || TREE_CODE (elt) == TEMPLATE_DECL) + continue; + if (TREE_CODE (elt) == NONTYPE_ARGUMENT_PACK) + { + if (!fold_targs_r (ARGUMENT_PACK_ARGS (elt), complain)) + return false; + } + else if (/* We can only safely preevaluate scalar prvalues. */ + SCALAR_TYPE_P (TREE_TYPE (elt)) + && !glvalue_p (elt) + && !TREE_CONSTANT (elt)) + { + elt = cxx_constant_value_sfinae (elt, complain); + if (elt == error_mark_node) + return false; + } + } + + return true; +} + +/* Try to do constant evaluation of any explicit template arguments in FN + before overload resolution, to get any errors only once. Return true iff + we didn't have any problems folding. */ + +static bool +maybe_fold_fn_template_args (tree fn, tsubst_flags_t complain) +{ + if (processing_template_decl || fn == NULL_TREE) + return true; + if (fn == error_mark_node) + return false; + if (TREE_CODE (fn) == OFFSET_REF + || TREE_CODE (fn) == COMPONENT_REF) + fn = TREE_OPERAND (fn, 1); + if (BASELINK_P (fn)) + fn = BASELINK_FUNCTIONS (fn); + if (TREE_CODE (fn) != TEMPLATE_ID_EXPR) + return true; + tree targs = TREE_OPERAND (fn, 1); + if (targs == NULL_TREE) + return true; + if (targs == error_mark_node) + return false; + return fold_targs_r (targs, complain); +} + /* Like tsubst but deals with expressions and performs semantic analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)" or "F (ARGS)". */ @@ -20343,6 +20400,9 @@ tsubst_copy_and_build (tree t, && !mark_used (function, complain) && !(complain & tf_error)) RETURN (error_mark_node); + if (!maybe_fold_fn_template_args (function, complain)) + return error_mark_node; + /* Put back tf_decltype for the actual call. */ complain |= decltype_flag; diff --git a/gcc/testsuite/g++.dg/template/explicit-args6.C b/gcc/testsuite/g++.dg/template/explicit-args6.C new file mode 100644 index 00000000000..d853564e3be --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-args6.C @@ -0,0 +1,34 @@ +// PR c++/101460 +// { dg-do compile { target c++11 } } + +template struct enable_if { }; +template<> struct enable_if { using type = void; }; + +template +using enable_if_t = typename enable_if::type; + +struct tuple { }; +struct pair { }; + +template enable_if_t get(tuple&) { } // { dg-bogus "candidate" } +template enable_if_t get(const tuple&) { } // { dg-bogus "candidate" } +template enable_if_t get(pair&) { } // { dg-bogus "candidate" } +template enable_if_t get(const pair&) { } // { dg-bogus "candidate" } + +template +constexpr unsigned +frob() +{ + static_assert(N == 1, "user-friendly diagnostic"); // { dg-error "user-friendly" } + // narrowing check, reject negative values + return unsigned{N}; // { dg-prune-output "narrowing" } +} // { dg-prune-output "flows off the end" } +// { dg-prune-output "not a return-statement" } + +template void get_n(tuple& t) { get()>(t); } // { dg-error "" } + +int main() +{ + tuple t; + get_n<-1>(t); +}