public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3234] c++: fold function template args sooner [PR101460]
@ 2021-08-30 21:23 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2021-08-30 21:23 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a8de832470f78a40a0e2c8de866a471bf74bf0ab

commit r12-3234-ga8de832470f78a40a0e2c8de866a471bf74bf0ab
Author: Jason Merrill <jason@redhat.com>
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<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);
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-30 21:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-30 21:23 [gcc r12-3234] c++: fold function template args sooner [PR101460] Jason Merrill

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).