[pushed] c++: only cache constexpr calls that are constant exprs

Message ID 20230717211808.946183-1-jason@redhat.com
State Accepted
Headers
Series [pushed] c++: only cache constexpr calls that are constant exprs |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Jason Merrill July 17, 2023, 9:18 p.m. UTC
  Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

In reviewing Nathaniel's patch for PR70331, it occurred to me that instead
of looking for various specific problematic things in the result of a
constexpr call to decide whether to cache it, we should use
reduced_constant_expression_p.

The change to that function is to avoid crashing on uninitialized objects of
non-class type.

In a trial version of this patch I checked to see what cases this stopped
caching; some were instances of partially-initialized return values, which
seem fine to not cache.  Some were returning pointers to expiring local
variables, which we definitely want not to cache.  And one was bit-cast3.C,
which will be handled in a follow-up patch.

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_eval_call_expression): Only cache
	reduced_constant_expression_p results.
	(reduced_constant_expression_p): Handle CONSTRUCTOR of scalar type.
	(cxx_eval_constant_expression): Fold vectors here.
	(cxx_eval_bare_aggregate): Not here.
---
 gcc/cp/constexpr.cc | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)


base-commit: caabf0973a4e9a26421c94d540e3e20051e93e77
  

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c6f323ebf43..9d85c3be5cc 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3033,7 +3033,7 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
     }
   else
     {
-      bool cacheable = true;
+      bool cacheable = !!entry;
       if (result && result != error_mark_node)
 	/* OK */;
       else if (!DECL_SAVED_TREE (fun))
@@ -3185,7 +3185,7 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	     for the constexpr evaluation and should not be cached.
 	     It is fine if the call allocates something and deallocates it
 	     too.  */
-	  if (entry
+	  if (cacheable
 	      && (save_heap_alloc_count != ctx->global->heap_vars.length ()
 		  || (save_heap_dealloc_count
 		      != ctx->global->heap_dealloc_count)))
@@ -3204,10 +3204,6 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 		      cacheable = false;
 		      break;
 		    }
-	      /* Also don't cache a call that returns a deallocated pointer.  */
-	      if (cacheable && (cp_walk_tree_without_duplicates
-				(&result, find_heap_var_refs, NULL)))
-		cacheable = false;
 	    }
 
 	    /* Rewrite all occurrences of the function's RESULT_DECL with the
@@ -3217,6 +3213,10 @@  cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 		&& !is_empty_class (TREE_TYPE (res)))
 	      if (replace_decl (&result, res, ctx->object))
 		cacheable = false;
+
+	  /* Only cache a permitted result of a constant expression.  */
+	  if (cacheable && !reduced_constant_expression_p (result))
+	    cacheable = false;
 	}
       else
 	/* Couldn't get a function copy to evaluate.  */
@@ -3268,8 +3268,9 @@  reduced_constant_expression_p (tree t)
     case CONSTRUCTOR:
       /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
       tree field;
-      if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
-	/* An initialized vector would have a VECTOR_CST.  */
+      if (!AGGREGATE_TYPE_P (TREE_TYPE (t)))
+	/* A constant vector would be folded to VECTOR_CST.
+	   A CONSTRUCTOR of scalar type means uninitialized.  */
 	return false;
       if (CONSTRUCTOR_NO_CLEARING (t))
 	{