aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2021-08-30 09:44:28 -0400
committerJason Merrill <jason@redhat.com>2021-08-30 17:23:28 -0400
commita8de832470f78a40a0e2c8de866a471bf74bf0ab (patch)
treeb4c322aa99ae5649ec56af1b228c1304f2a2c68d /gcc/cp
parenta7083b83e45852540a4a09ee11b74dc28d777399 (diff)
downloadgcc-a8de832470f78a40a0e2c8de866a471bf74bf0ab.zip
gcc-a8de832470f78a40a0e2c8de866a471bf74bf0ab.tar.gz
gcc-a8de832470f78a40a0e2c8de866a471bf74bf0ab.tar.bz2
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.
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/constexpr.c12
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/pt.c60
3 files changed, 73 insertions, 0 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index b9c0062..9606719 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/cp-tree.h b/gcc/cp/cp-tree.h
index 75ee887..6a17937 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/pt.c b/gcc/cp/pt.c
index 020a4bf..d7d0dce 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<TARGS> (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;