public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [pushed] c++: fold function template args sooner [PR101460]
@ 2021-08-30 21:23 Jason Merrill
  2021-08-30 21:25 ` [pushed] c++: preserve location through constexpr Jason Merrill
  0 siblings, 1 reply; 3+ messages in thread
From: Jason Merrill @ 2021-08-30 21:23 UTC (permalink / raw)
  To: gcc-patches

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


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [pushed] c++: preserve location through constexpr
  2021-08-30 21:23 [pushed] c++: fold function template args sooner [PR101460] Jason Merrill
@ 2021-08-30 21:25 ` Jason Merrill
  2021-08-30 22:45   ` Marek Polacek
  0 siblings, 1 reply; 3+ messages in thread
From: Jason Merrill @ 2021-08-30 21:25 UTC (permalink / raw)
  To: gcc-patches

While working on the patch for PR101460, I noticed that we were losing the
expression location when folding class prvalue expressions.  The final patch
doesn't fold class prvalues, but this still seems a worthwhile change.  I
don't add location wrappers for scalar prvalues because many callers are
trying to fold them away.

Tested x86_64-pc-linux-gnu, applying to trunk.

gcc/cp/ChangeLog:

	* constexpr.c (cxx_eval_outermost_constant_expr): Copy
	expr location to result.
---
 gcc/cp/constexpr.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 9606719bc73..e78fdf021b2 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -7445,6 +7445,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 	}
     }
 
+  /* Remember the original location if that wouldn't need a wrapper.  */
+  if (location_t loc = EXPR_LOCATION (t))
+    if (CAN_HAVE_LOCATION_P (r))
+      SET_EXPR_LOCATION (r, loc);
+
   return r;
 }
 

base-commit: a8de832470f78a40a0e2c8de866a471bf74bf0ab
-- 
2.27.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [pushed] c++: preserve location through constexpr
  2021-08-30 21:25 ` [pushed] c++: preserve location through constexpr Jason Merrill
@ 2021-08-30 22:45   ` Marek Polacek
  0 siblings, 0 replies; 3+ messages in thread
From: Marek Polacek @ 2021-08-30 22:45 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Mon, Aug 30, 2021 at 05:25:01PM -0400, Jason Merrill via Gcc-patches wrote:
> While working on the patch for PR101460, I noticed that we were losing the
> expression location when folding class prvalue expressions.  The final patch
> doesn't fold class prvalues, but this still seems a worthwhile change.  I
> don't add location wrappers for scalar prvalues because many callers are
> trying to fold them away.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.c (cxx_eval_outermost_constant_expr): Copy
> 	expr location to result.
> ---
>  gcc/cp/constexpr.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 9606719bc73..e78fdf021b2 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -7445,6 +7445,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
>  	}
>      }
>  
> +  /* Remember the original location if that wouldn't need a wrapper.  */
> +  if (location_t loc = EXPR_LOCATION (t))
> +    if (CAN_HAVE_LOCATION_P (r))
> +      SET_EXPR_LOCATION (r, loc);

Can we use protected_set_expr_location or did you not want that?

Marek


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-08-30 22:45 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-30 21:23 [pushed] c++: fold function template args sooner [PR101460] Jason Merrill
2021-08-30 21:25 ` [pushed] c++: preserve location through constexpr Jason Merrill
2021-08-30 22:45   ` Marek Polacek

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