From: Jason Merrill <jason@redhat.com>
To: gcc-patches@gcc.gnu.org
Subject: [pushed] c++: fold function template args sooner [PR101460]
Date: Mon, 30 Aug 2021 17:23:05 -0400 [thread overview]
Message-ID: <20210830212305.569090-1-jason@redhat.com> (raw)
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.
Tested x86_64-pc-linux-gnu, applying to trunk.
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.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/constexpr.c | 12 ++++
gcc/cp/pt.c | 60 +++++++++++++++++++
.../g++.dg/template/explicit-args6.C | 34 +++++++++++
4 files changed, 107 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/template/explicit-args6.C
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<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;
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<bool> struct enable_if { };
+template<> struct enable_if<true> { using type = void; };
+
+template<bool B>
+using enable_if_t = typename enable_if<B>::type;
+
+struct tuple { };
+struct pair { };
+
+template<unsigned N> enable_if_t<N == 1> get(tuple&) { } // { dg-bogus "candidate" }
+template<unsigned N> enable_if_t<N == 1> get(const tuple&) { } // { dg-bogus "candidate" }
+template<unsigned N> enable_if_t<N == 1> get(pair&) { } // { dg-bogus "candidate" }
+template<unsigned N> enable_if_t<N == 1> get(const pair&) { } // { dg-bogus "candidate" }
+
+template<int N>
+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<int N> void get_n(tuple& t) { get<frob<N>()>(t); } // { dg-error "" }
+
+int main()
+{
+ tuple t;
+ get_n<-1>(t);
+}
base-commit: e18e56c76be35e6a799e07a01c24e0fff3eb1978
--
2.27.0
next reply other threads:[~2021-08-30 21:23 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-30 21:23 Jason Merrill [this message]
2021-08-30 21:25 ` [pushed] c++: preserve location through constexpr Jason Merrill
2021-08-30 22:45 ` Marek Polacek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210830212305.569090-1-jason@redhat.com \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).