This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for c++/64333 (wrong constexpr result)


Now that in C++14 we can have non-constant arguments to constexpr functions called from another constexpr function, we need to avoid caching the result, as a later call might produce a different value for the same non-constant argument, e.g. the address of a local variable.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit f702ac694e3d7e59453d5fc494d81cbfdab9a88c
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Dec 17 10:19:28 2014 -0500

    	PR c++/64333
    	* constexpr.c (cxx_bind_parameters_in_call): non_constant_args parm.
    	(cxx_eval_call_expression): Don't cache calls with non-constant args.
    	(cxx_eval_constant_expression) [COMPOUND_EXPR]: Pass true for lval.
    	(cxx_eval_unary_expression, cxx_eval_binary_expression)
    	(cxx_eval_conditional_expression): Pass	false for lval.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 3ab80f7..afbcf51 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1050,7 +1050,8 @@ adjust_temp_type (tree type, tree temp)
 static void
 cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
                              constexpr_call *new_call,
-			     bool *non_constant_p, bool *overflow_p)
+			     bool *non_constant_p, bool *overflow_p,
+			     bool *non_constant_args)
 {
   const int nargs = call_expr_nargs (t);
   tree fun = new_call->fundef->decl;
@@ -1099,6 +1100,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
       /* Make sure the binding has the same type as the parm.  */
       if (TREE_CODE (type) != REFERENCE_TYPE)
 	arg = adjust_temp_type (type, arg);
+      if (!TREE_CONSTANT (arg))
+	*non_constant_args = true;
       *p = build_tree_list (parms, arg);
       p = &TREE_CHAIN (*p);
     next:
@@ -1155,10 +1158,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 {
   location_t loc = EXPR_LOC_OR_LOC (t, input_location);
   tree fun = get_function_named_in_call (t);
-  tree result;
   constexpr_call new_call = { NULL, NULL, NULL, 0 };
-  constexpr_call **slot;
-  constexpr_call *entry;
   bool depth_ok;
 
   if (fun == NULL_TREE)
@@ -1264,36 +1264,45 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       ctx = &new_ctx;
     }
 
+  bool non_constant_args = false;
   cxx_bind_parameters_in_call (ctx, t, &new_call,
-			       non_constant_p, overflow_p);
+			       non_constant_p, overflow_p, &non_constant_args);
   if (*non_constant_p)
     return t;
 
   depth_ok = push_cx_call_context (t);
 
-  new_call.hash
-    = iterative_hash_template_arg (new_call.bindings,
-				   constexpr_fundef_hasher::hash (new_call.fundef));
+  tree result = NULL_TREE;
 
-  /* If we have seen this call before, we are done.  */
-  maybe_initialize_constexpr_call_table ();
-  slot = constexpr_call_table->find_slot (&new_call, INSERT);
-  entry = *slot;
-  if (entry == NULL)
+  constexpr_call *entry = NULL;
+  if (!non_constant_args)
     {
-      /* We need to keep a pointer to the entry, not just the slot, as the
-	 slot can move in the call to cxx_eval_builtin_function_call.  */
-      *slot = entry = ggc_alloc<constexpr_call> ();
-      *entry = new_call;
-    }
-  /* Calls which are in progress have their result set to NULL
-     so that we can detect circular dependencies.  */
-  else if (entry->result == NULL)
-    {
-      if (!ctx->quiet)
-	error ("call has circular dependency");
-      *non_constant_p = true;
-      entry->result = result = error_mark_node;
+      new_call.hash = iterative_hash_template_arg
+	(new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef));
+
+      /* If we have seen this call before, we are done.  */
+      maybe_initialize_constexpr_call_table ();
+      constexpr_call **slot
+	= constexpr_call_table->find_slot (&new_call, INSERT);
+      entry = *slot;
+      if (entry == NULL)
+	{
+	  /* We need to keep a pointer to the entry, not just the slot, as the
+	     slot can move in the call to cxx_eval_builtin_function_call.  */
+	  *slot = entry = ggc_alloc<constexpr_call> ();
+	  *entry = new_call;
+	}
+      /* Calls which are in progress have their result set to NULL
+	 so that we can detect circular dependencies.  */
+      else if (entry->result == NULL)
+	{
+	  if (!ctx->quiet)
+	    error ("call has circular dependency");
+	  *non_constant_p = true;
+	  entry->result = result = error_mark_node;
+	}
+      else
+	result = entry->result;
     }
 
   if (!depth_ok)
@@ -1303,11 +1312,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	       "-fconstexpr-depth= to increase the maximum)",
 	       max_constexpr_depth);
       *non_constant_p = true;
-      entry->result = result = error_mark_node;
+      result = error_mark_node;
     }
   else
     {
-      result = entry->result;
       if (!result || result == error_mark_node)
 	{
 	  if (!use_new_call)
@@ -1395,7 +1403,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       if (result == error_mark_node)
 	*non_constant_p = true;
       if (*non_constant_p)
-	entry->result = result = error_mark_node;
+	result = error_mark_node;
       else if (result)
 	{
 	  /* If this was a call to initialize an object, set the type of
@@ -1409,10 +1417,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	      result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)),
 					 result);
 	    }
-	  entry->result = result;
 	}
       else
 	result = void_node;
+      if (entry)
+	entry->result = result;
     }
 
   pop_cx_call_context ();
@@ -1558,13 +1567,13 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
 
 static tree
 cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
-			   bool lval,
+			   bool /*lval*/,
 			   bool *non_constant_p, bool *overflow_p)
 {
   tree r;
   tree orig_arg = TREE_OPERAND (t, 0);
-  tree arg = cxx_eval_constant_expression (ctx, orig_arg,
-					   lval, non_constant_p, overflow_p);
+  tree arg = cxx_eval_constant_expression (ctx, orig_arg, /*lval*/false,
+					   non_constant_p, overflow_p);
   VERIFY_CONSTANT (arg);
   location_t loc = EXPR_LOCATION (t);
   enum tree_code code = TREE_CODE (t);
@@ -1586,19 +1595,17 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
-			    bool lval,
+			    bool /*lval*/,
 			    bool *non_constant_p, bool *overflow_p)
 {
   tree r;
   tree orig_lhs = TREE_OPERAND (t, 0);
   tree orig_rhs = TREE_OPERAND (t, 1);
   tree lhs, rhs;
-  lhs = cxx_eval_constant_expression (ctx, orig_lhs,
-				      lval,
+  lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false,
 				      non_constant_p, overflow_p);
   VERIFY_CONSTANT (lhs);
-  rhs = cxx_eval_constant_expression (ctx, orig_rhs,
-				      lval,
+  rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false,
 				      non_constant_p, overflow_p);
   VERIFY_CONSTANT (rhs);
 
@@ -1630,7 +1637,7 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
 				 tree *jump_target)
 {
   tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-					   lval,
+					   /*lval*/false,
 					   non_constant_p, overflow_p);
   VERIFY_CONSTANT (val);
   /* Don't VERIFY_CONSTANT the other operands.  */
@@ -3085,7 +3092,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	r = *p;
       else
 	{
-	  r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), addr,
+	  r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false,
 					    non_constant_p, overflow_p);
 	  ctx->values->put (t, r);
 	}
@@ -3174,7 +3181,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  {
 	    /* Check that the LHS is constant and then discard it.  */
 	    cxx_eval_constant_expression (ctx, op0,
-					  false, non_constant_p, overflow_p,
+					  true, non_constant_p, overflow_p,
 					  jump_target);
 	    op1 = TREE_OPERAND (t, 1);
 	    r = cxx_eval_constant_expression (ctx, op1,
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
new file mode 100644
index 0000000..bdef8a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-initlist1.C
@@ -0,0 +1,22 @@
+// PR c++/64333
+// { dg-do compile { target c++14 } }
+#include <initializer_list>
+
+constexpr int max(std::initializer_list<int> ints)
+{
+        int ret = *(ints.begin());
+        for (int i = 0; i < ints.size(); ++i) {
+                if (*(ints.begin()+i) > ret) {
+                        ret = *(ints.begin()+i);
+                }
+        }
+        return ret;
+}
+
+int main()
+{
+        constexpr int z = max({7,6,5,4,3,2,1});
+        constexpr int z2 = max({5,4,3,2,1});
+        static_assert(z == 7, "");
+        static_assert(z2 == 5, "");
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
new file mode 100644
index 0000000..2e53e48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++14 } }
+
+constexpr int f(int* p) { return *p; }
+constexpr int g(int n)
+{
+  int sum = 0;
+  for (int i = 1; i <= n; ++i)
+    sum += f(&i);
+  return sum;
+}
+
+static_assert(g(3) == 3+2+1,"");

commit 0b751ac9d5dc1bc85349566669be1b5839757041
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Dec 17 13:30:20 2014 -0500

    	* constexpr.c: Change "addr" parm names to "lval".

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1323111..3ab80f7 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -999,7 +999,7 @@ lookup_parameter_binding (const constexpr_call *call, tree t)
 
 static tree
 cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
-				bool addr,
+				bool lval,
 				bool *non_constant_p, bool *overflow_p)
 {
   const int nargs = call_expr_nargs (t);
@@ -1009,7 +1009,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t,
   for (i = 0; i < nargs; ++i)
     {
       args[i] = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, i),
-					      addr,
+					      lval,
 					      non_constant_p, overflow_p);
       if (ctx->quiet && *non_constant_p)
 	return t;
@@ -1071,7 +1071,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 	  x = ctx->object;
 	  x = cp_build_addr_expr (x, tf_warning_or_error);
 	}
-      bool addr = false;
+      bool lval = false;
       if (parms && DECL_BY_REFERENCE (parms) && !use_new_call)
 	{
 	  /* cp_genericize made this a reference for argument passing, but
@@ -1082,9 +1082,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 	  gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE);
 	  type = TREE_TYPE (type);
 	  x = convert_from_reference (x);
-	  addr = true;
+	  lval = true;
 	}
-      arg = cxx_eval_constant_expression (ctx, x, addr,
+      arg = cxx_eval_constant_expression (ctx, x, lval,
 					  non_constant_p, overflow_p);
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p && ctx->quiet)
@@ -1150,7 +1150,7 @@ cx_error_context (void)
 
 static tree
 cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
-			  bool addr,
+			  bool lval,
 			  bool *non_constant_p, bool *overflow_p)
 {
   location_t loc = EXPR_LOC_OR_LOC (t, input_location);
@@ -1178,7 +1178,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
     {
       /* Might be a constexpr function pointer.  */
       fun = cxx_eval_constant_expression (ctx, fun,
-					  /*addr*/false, non_constant_p,
+					  /*lval*/false, non_constant_p,
 					  overflow_p);
       STRIP_NOPS (fun);
       if (TREE_CODE (fun) == ADDR_EXPR)
@@ -1200,7 +1200,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 
   if (is_builtin_fn (fun))
     return cxx_eval_builtin_function_call (ctx, t,
-					   addr, non_constant_p, overflow_p);
+					   lval, non_constant_p, overflow_p);
   if (!DECL_DECLARED_CONSTEXPR_P (fun))
     {
       if (!ctx->quiet)
@@ -1219,7 +1219,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	{
 	  tree arg = convert_from_reference (get_nth_callarg (t, 1));
 	  return cxx_eval_constant_expression (ctx, arg,
-					       addr, non_constant_p,
+					       lval, non_constant_p,
 					       overflow_p);
 	}
       else if (TREE_CODE (t) == AGGR_INIT_EXPR
@@ -1315,7 +1315,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	      new_ctx.call = &new_call;
 	      result = (cxx_eval_constant_expression
 			(&new_ctx, new_call.fundef->body,
-			 addr,
+			 lval,
 			 non_constant_p, overflow_p));
 	    }
 	  else
@@ -1358,7 +1358,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 
 	      tree jump_target = NULL_TREE;
 	      cxx_eval_constant_expression (ctx, body,
-					    addr, non_constant_p, overflow_p,
+					    lval, non_constant_p, overflow_p,
 					    &jump_target);
 
 	      if (DECL_CONSTRUCTOR_P (fun))
@@ -1367,7 +1367,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 		   side-effects rather than the value.  We could get at the
 		   value by evaluating *this, but we don't bother; there's
 		   no need to put such a call in the hash table.  */
-		result = addr ? ctx->object : ctx->ctor;
+		result = lval ? ctx->object : ctx->ctor;
 	      else
 		{
 		  result = *ctx->values->get (slot ? slot : res);
@@ -1558,13 +1558,13 @@ cxx_eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
 
 static tree
 cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
-			   bool addr,
+			   bool lval,
 			   bool *non_constant_p, bool *overflow_p)
 {
   tree r;
   tree orig_arg = TREE_OPERAND (t, 0);
   tree arg = cxx_eval_constant_expression (ctx, orig_arg,
-					   addr, non_constant_p, overflow_p);
+					   lval, non_constant_p, overflow_p);
   VERIFY_CONSTANT (arg);
   location_t loc = EXPR_LOCATION (t);
   enum tree_code code = TREE_CODE (t);
@@ -1586,7 +1586,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
-			    bool addr,
+			    bool lval,
 			    bool *non_constant_p, bool *overflow_p)
 {
   tree r;
@@ -1594,11 +1594,11 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
   tree orig_rhs = TREE_OPERAND (t, 1);
   tree lhs, rhs;
   lhs = cxx_eval_constant_expression (ctx, orig_lhs,
-				      addr,
+				      lval,
 				      non_constant_p, overflow_p);
   VERIFY_CONSTANT (lhs);
   rhs = cxx_eval_constant_expression (ctx, orig_rhs,
-				      addr,
+				      lval,
 				      non_constant_p, overflow_p);
   VERIFY_CONSTANT (rhs);
 
@@ -1625,22 +1625,22 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
-				 bool addr,
+				 bool lval,
 				 bool *non_constant_p, bool *overflow_p,
 				 tree *jump_target)
 {
   tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-					   addr,
+					   lval,
 					   non_constant_p, overflow_p);
   VERIFY_CONSTANT (val);
   /* Don't VERIFY_CONSTANT the other operands.  */
   if (integer_zerop (val))
     return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
-					 addr,
+					 lval,
 					 non_constant_p, overflow_p,
 					 jump_target);
   return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-				       addr,
+				       lval,
 				       non_constant_p, overflow_p,
 				       jump_target);
 }
@@ -1650,12 +1650,12 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
-			  bool addr,
+			  bool lval,
 			  bool *non_constant_p, bool *overflow_p)
 {
   tree oldary = TREE_OPERAND (t, 0);
   tree ary = cxx_eval_constant_expression (ctx, oldary,
-					   addr,
+					   lval,
 					   non_constant_p, overflow_p);
   tree index, oldidx;
   HOST_WIDE_INT i;
@@ -1668,9 +1668,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 					false,
 					non_constant_p, overflow_p);
   VERIFY_CONSTANT (index);
-  if (addr && ary == oldary && index == oldidx)
+  if (lval && ary == oldary && index == oldidx)
     return t;
-  else if (addr)
+  else if (lval)
     return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
   elem_type = TREE_TYPE (TREE_TYPE (ary));
   if (TREE_CODE (ary) == CONSTRUCTOR)
@@ -1696,7 +1696,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 	     initializer, it's value-initialized.  */
 	  tree val = build_value_init (elem_type, tf_warning_or_error);
 	  return cxx_eval_constant_expression (ctx, val,
-					       addr,
+					       lval,
 					       non_constant_p, overflow_p);
 	}
 
@@ -1733,7 +1733,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
-			      bool addr,
+			      bool lval,
 			      bool *non_constant_p, bool *overflow_p)
 {
   unsigned HOST_WIDE_INT i;
@@ -1742,11 +1742,11 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree part = TREE_OPERAND (t, 1);
   tree orig_whole = TREE_OPERAND (t, 0);
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
-					     addr,
+					     lval,
 					     non_constant_p, overflow_p);
   if (whole == orig_whole)
     return t;
-  if (addr)
+  if (lval)
     return fold_build3 (COMPONENT_REF, TREE_TYPE (t),
 			whole, part, NULL_TREE);
   /* Don't VERIFY_CONSTANT here; we only want to check that we got a
@@ -1801,7 +1801,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   /* If there's no explicit init for this field, it's value-initialized.  */
   value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
   return cxx_eval_constant_expression (ctx, value,
-				       addr,
+				       lval,
 				       non_constant_p, overflow_p);
 }
 
@@ -1811,7 +1811,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
-			bool addr,
+			bool lval,
 			bool *non_constant_p, bool *overflow_p)
 {
   tree orig_whole = TREE_OPERAND (t, 0);
@@ -1819,7 +1819,7 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
   bool fld_seen = false;
   HOST_WIDE_INT istart, isize;
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
-					     addr,
+					     lval,
 					     non_constant_p, overflow_p);
   tree start, field, value;
   unsigned HOST_WIDE_INT i;
@@ -1897,19 +1897,19 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t,
 static tree
 cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t,
                              tree bailout_value, tree continue_value,
-			     bool addr,
+			     bool lval,
 			     bool *non_constant_p, bool *overflow_p)
 {
   tree r;
   tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-					   addr,
+					   lval,
 					   non_constant_p, overflow_p);
   VERIFY_CONSTANT (lhs);
   if (tree_int_cst_equal (lhs, bailout_value))
     return lhs;
   gcc_assert (tree_int_cst_equal (lhs, continue_value));
   r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-				    addr, non_constant_p,
+				    lval, non_constant_p,
 				    overflow_p);
   VERIFY_CONSTANT (r);
   return r;
@@ -2031,7 +2031,7 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type)
 
 static tree
 cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
-			 bool addr,
+			 bool lval,
 			 bool *non_constant_p, bool *overflow_p)
 {
   vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
@@ -2052,7 +2052,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
 	   initializers can refer to it.  */
 	CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
       tree elt = cxx_eval_constant_expression (&new_ctx, value,
-					       addr,
+					       lval,
 					       non_constant_p, overflow_p);
       /* Don't VERIFY_CONSTANT here.  */
       if (ctx->quiet && *non_constant_p)
@@ -2111,7 +2111,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
-		     bool value_init, bool addr,
+		     bool value_init, bool lval,
 		     bool *non_constant_p, bool *overflow_p)
 {
   tree elttype = TREE_TYPE (atype);
@@ -2162,7 +2162,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 	    eltinit = cp_build_array_ref (input_location, init, idx,
 					  tf_warning_or_error);
 	  eltinit = cxx_eval_vec_init_1 (&new_ctx, elttype, eltinit, value_init,
-					 addr,
+					 lval,
 					 non_constant_p, overflow_p);
 	}
       else if (pre_init)
@@ -2171,7 +2171,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 	     we just pre-built above.  */
 	  eltinit = (cxx_eval_constant_expression
 		     (&new_ctx, init,
-		      addr, non_constant_p, overflow_p));
+		      lval, non_constant_p, overflow_p));
 	}
       else
 	{
@@ -2184,7 +2184,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 	    eltinit = move (eltinit);
 	  eltinit = force_rvalue (eltinit, tf_warning_or_error);
 	  eltinit = (cxx_eval_constant_expression
-		     (&new_ctx, eltinit, addr,
+		     (&new_ctx, eltinit, lval,
 		      non_constant_p, overflow_p));
 	}
       if (*non_constant_p && !ctx->quiet)
@@ -2209,14 +2209,14 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 
 static tree
 cxx_eval_vec_init (const constexpr_ctx *ctx, tree t,
-		   bool addr,
+		   bool lval,
 		   bool *non_constant_p, bool *overflow_p)
 {
   tree atype = TREE_TYPE (t);
   tree init = VEC_INIT_EXPR_INIT (t);
   tree r = cxx_eval_vec_init_1 (ctx, atype, init,
 				VEC_INIT_EXPR_VALUE_INIT (t),
-				addr, non_constant_p, overflow_p);
+				lval, non_constant_p, overflow_p);
   if (*non_constant_p)
     return t;
   else
@@ -2416,12 +2416,12 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base)
 
 static tree
 cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
-		       bool addr,
+		       bool lval,
 		       bool *non_constant_p, bool *overflow_p)
 {
   tree orig_op0 = TREE_OPERAND (t, 0);
   tree op0 = cxx_eval_constant_expression (ctx, orig_op0,
-					   /*addr*/false, non_constant_p,
+					   /*lval*/false, non_constant_p,
 					   overflow_p);
   bool empty_base = false;
   tree r;
@@ -2435,7 +2435,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 
   if (r)
     r = cxx_eval_constant_expression (ctx, r,
-				      addr, non_constant_p, overflow_p);
+				      lval, non_constant_p, overflow_p);
   else
     {
       tree sub = op0;
@@ -2459,7 +2459,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   /* If we're pulling out the value of an empty base, make sure
      that the whole object is constant and then return an empty
      CONSTRUCTOR.  */
-  if (empty_base && !addr)
+  if (empty_base && !lval)
     {
       VERIFY_CONSTANT (r);
       r = build_constructor (TREE_TYPE (t), NULL);
@@ -2468,9 +2468,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
 
   if (r == NULL_TREE)
     {
-      if (addr && op0 != orig_op0)
+      if (lval && op0 != orig_op0)
 	return build1 (INDIRECT_REF, TREE_TYPE (t), op0);
-      if (!addr)
+      if (!lval)
 	VERIFY_CONSTANT (t);
       return t;
     }
@@ -2526,7 +2526,7 @@ non_const_var_error (tree r)
 
 static tree
 cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
-			     bool addr,
+			     bool lval,
 			     bool *non_constant_p, bool *overflow_p)
 {
   int i;
@@ -2536,7 +2536,7 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t,
   for (i = 0; i < 3; i++)
     {
       args[i] = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, i),
-					      addr,
+					      lval,
 					      non_constant_p, overflow_p);
       VERIFY_CONSTANT (args[i]);
     }
@@ -2561,7 +2561,7 @@ var_in_constexpr_fn (tree t)
 
 static tree
 cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
-			   bool addr,
+			   bool lval,
 			   bool *non_constant_p, bool *overflow_p)
 {
   constexpr_ctx new_ctx = *ctx;
@@ -2658,7 +2658,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 
   if (*non_constant_p)
     return t;
-  else if (addr)
+  else if (lval)
     return target;
   else
     return init;
@@ -2668,7 +2668,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
-			      bool addr,
+			      bool lval,
 			      bool *non_constant_p, bool *overflow_p)
 {
   enum tree_code code = TREE_CODE (t);
@@ -2711,7 +2711,7 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
   if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
     {
       /* Prefix ops are lvalues.  */
-      if (addr)
+      if (lval)
 	return op;
       else
 	/* But we optimize when the caller wants an rvalue.  */
@@ -2886,7 +2886,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
 
 static tree
 cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
-			      bool addr,
+			      bool lval,
 			      bool *non_constant_p, bool *overflow_p,
 			      tree *jump_target)
 {
@@ -2913,7 +2913,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
   switch (TREE_CODE (t))
     {
     case RESULT_DECL:
-      if (addr)
+      if (lval)
 	return t;
       /* We ask for an rvalue for the RESULT_DECL when indirecting
 	 through an invisible reference.  */
@@ -2921,7 +2921,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return (*ctx->values->get (t));
 
     case VAR_DECL:
-      if (addr)
+      if (lval)
 	return t;
       /* else fall through. */
     case CONST_DECL:
@@ -2954,11 +2954,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (!use_new_call && ctx
 	  && ctx->call && DECL_CONTEXT (t) == ctx->call->fundef->decl)
 	r = lookup_parameter_binding (ctx->call, t);
-      else if (addr && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
+      else if (lval && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
 	/* glvalue use.  */;
       else if (tree *p = ctx->values->get (r))
 	r = *p;
-      else if (addr)
+      else if (lval)
 	/* Defer in case this is only used for its type.  */;
       else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
 	/* Defer, there's no lvalue->rvalue conversion.  */;
@@ -2978,7 +2978,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
     case CALL_EXPR:
     case AGGR_INIT_EXPR:
-      r = cxx_eval_call_expression (ctx, t, addr,
+      r = cxx_eval_call_expression (ctx, t, lval,
 				    non_constant_p, overflow_p);
       break;
 
@@ -3034,7 +3034,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  ctx->values->put (new_ctx.object, new_ctx.ctor);
 	  ctx = &new_ctx;
 	}
-      /* Pass false for 'addr' because this indicates
+      /* Pass false for 'lval' because this indicates
 	 initialization of a temporary.  */
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					false,
@@ -3042,7 +3042,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (!*non_constant_p)
 	/* Adjust the type of the result to the type of the temporary.  */
 	r = adjust_temp_type (TREE_TYPE (t), r);
-      if (addr)
+      if (lval)
 	{
 	  tree slot = TARGET_EXPR_SLOT (t);
 	  ctx->values->put (slot, r);
@@ -3062,19 +3062,19 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	}
       /* else fall through */
     case MODIFY_EXPR:
-      r = cxx_eval_store_expression (ctx, t, addr,
+      r = cxx_eval_store_expression (ctx, t, lval,
 				     non_constant_p, overflow_p);
       break;
 
     case SCOPE_REF:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-					addr,
+					lval,
 					non_constant_p, overflow_p);
       break;
 
     case RETURN_EXPR:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-					addr,
+					lval,
 					non_constant_p, overflow_p);
       *jump_target = t;
       break;
@@ -3098,7 +3098,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case EXPR_STMT:
     case EH_SPEC_BLOCK:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-					addr,
+					lval,
 					non_constant_p, overflow_p,
 					jump_target);
       break;
@@ -3107,7 +3107,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	 check for a constant operand or result; an address can be
 	 constant without its operand being, and vice versa.  */
     case INDIRECT_REF:
-      r = cxx_eval_indirect_ref (ctx, t, addr,
+      r = cxx_eval_indirect_ref (ctx, t, lval,
 				 non_constant_p, overflow_p);
       break;
 
@@ -3115,7 +3115,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       {
 	tree oldop = TREE_OPERAND (t, 0);
 	tree op = cxx_eval_constant_expression (ctx, oldop,
-						/*addr*/true,
+						/*lval*/true,
 						non_constant_p, overflow_p);
 	/* Don't VERIFY_CONSTANT here.  */
 	if (*non_constant_p)
@@ -3138,7 +3138,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
     case FIXED_CONVERT_EXPR:
-      r = cxx_eval_unary_expression (ctx, t, addr,
+      r = cxx_eval_unary_expression (ctx, t, lval,
 				     non_constant_p, overflow_p);
       break;
 
@@ -3168,7 +3168,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0))
 	    || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
 	  r = cxx_eval_constant_expression (ctx, op0,
-					    addr, non_constant_p, overflow_p,
+					    lval, non_constant_p, overflow_p,
 					    jump_target);
 	else
 	  {
@@ -3178,7 +3178,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 					  jump_target);
 	    op1 = TREE_OPERAND (t, 1);
 	    r = cxx_eval_constant_expression (ctx, op1,
-					      addr, non_constant_p, overflow_p,
+					      lval, non_constant_p, overflow_p,
 					      jump_target);
 	  }
       }
@@ -3223,7 +3223,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case LTGT_EXPR:
     case RANGE_EXPR:
     case COMPLEX_EXPR:
-      r = cxx_eval_binary_expression (ctx, t, addr,
+      r = cxx_eval_binary_expression (ctx, t, lval,
 				      non_constant_p, overflow_p);
       break;
 
@@ -3233,7 +3233,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case TRUTH_ANDIF_EXPR:
       r = cxx_eval_logical_expression (ctx, t, boolean_false_node,
 				       boolean_true_node,
-				       addr,
+				       lval,
 				       non_constant_p, overflow_p);
       break;
 
@@ -3241,12 +3241,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case TRUTH_ORIF_EXPR:
       r = cxx_eval_logical_expression (ctx, t, boolean_true_node,
 				       boolean_false_node,
-				       addr,
+				       lval,
 				       non_constant_p, overflow_p);
       break;
 
     case ARRAY_REF:
-      r = cxx_eval_array_reference (ctx, t, addr,
+      r = cxx_eval_array_reference (ctx, t, lval,
 				    non_constant_p, overflow_p);
       break;
 
@@ -3261,24 +3261,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  *non_constant_p = true;
 	  return t;
 	}
-      r = cxx_eval_component_reference (ctx, t, addr,
+      r = cxx_eval_component_reference (ctx, t, lval,
 					non_constant_p, overflow_p);
       break;
 
     case BIT_FIELD_REF:
-      r = cxx_eval_bit_field_ref (ctx, t, addr,
+      r = cxx_eval_bit_field_ref (ctx, t, lval,
 				  non_constant_p, overflow_p);
       break;
 
     case COND_EXPR:
     case VEC_COND_EXPR:
-      r = cxx_eval_conditional_expression (ctx, t, addr,
+      r = cxx_eval_conditional_expression (ctx, t, lval,
 					   non_constant_p, overflow_p,
 					   jump_target);
       break;
 
     case CONSTRUCTOR:
-      r = cxx_eval_bare_aggregate (ctx, t, addr,
+      r = cxx_eval_bare_aggregate (ctx, t, lval,
 				   non_constant_p, overflow_p);
       break;
 
@@ -3288,13 +3288,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	 be NULL, meaning default-initialization, or it will be an lvalue
 	 or xvalue of the same type, meaning direct-initialization from the
 	 corresponding member.  */
-      r = cxx_eval_vec_init (ctx, t, addr,
+      r = cxx_eval_vec_init (ctx, t, lval,
 			     non_constant_p, overflow_p);
       break;
 
     case FMA_EXPR:
     case VEC_PERM_EXPR:
-      r = cxx_eval_trinary_expression (ctx, t, addr,
+      r = cxx_eval_trinary_expression (ctx, t, lval,
 				       non_constant_p, overflow_p);
       break;
 
@@ -3304,7 +3304,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       {
 	tree oldop = TREE_OPERAND (t, 0);
 	tree op = cxx_eval_constant_expression (ctx, oldop,
-						addr,
+						lval,
 						non_constant_p, overflow_p);
 	if (*non_constant_p)
 	  return t;
@@ -3344,7 +3344,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
     case BIND_EXPR:
       return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
-					   addr,
+					   lval,
 					   non_constant_p, overflow_p,
 					   jump_target);
 
@@ -3353,7 +3353,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case PREDECREMENT_EXPR:
     case POSTDECREMENT_EXPR:
       return cxx_eval_increment_expression (ctx, t,
-					    addr, non_constant_p, overflow_p);
+					    lval, non_constant_p, overflow_p);
 
     case LAMBDA_EXPR:
     case NEW_EXPR:
@@ -3376,7 +3376,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case PLACEHOLDER_EXPR:
-      if (!ctx || !ctx->ctor || (addr && !ctx->object))
+      if (!ctx || !ctx->ctor || (lval && !ctx->object))
 	{
 	  /* A placeholder without a referent.  We can get here when
 	     checking whether NSDMIs are noexcept, or in massage_init_elt;
@@ -3390,11 +3390,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  /* Use of the value or address of the current object.  We could
 	     use ctx->object unconditionally, but using ctx->ctor when we
 	     can is a minor optimization.  */
-	  tree ctor = addr ? ctx->object : ctx->ctor;
+	  tree ctor = lval ? ctx->object : ctx->ctor;
 	  gcc_assert (same_type_ignoring_top_level_qualifiers_p
 		      (TREE_TYPE (t), TREE_TYPE (ctor)));
 	  return cxx_eval_constant_expression
-	    (ctx, ctor, addr,
+	    (ctx, ctor, lval,
 	     non_constant_p, overflow_p);
 	}
       break;

commit 58c6c2bb496d9ea2869ab6c88fbc0213b9cac729
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Dec 17 10:28:38 2014 -0500

    	* constexpr.c: Tweak comments and formatting.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 732a79c..1323111 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1,6 +1,5 @@
-/* Perform the semantic phase of constexpr parsing, i.e., the process of
-   building tree structure, checking semantic consistency, and
-   building RTL.  These routines are used both during actual parsing
+/* Perform -*- C++ -*- constant expression evaluation, including calls to
+   constexpr functions.  These routines are used both during actual parsing
    and during the instantiation of template functions.
 
    Copyright (C) 1998-2014 Free Software Foundation, Inc.
@@ -866,11 +865,20 @@ struct constexpr_call_hasher : ggc_hasher<constexpr_call *>
    is a map of values of variables initialized within the expression.  */
 
 struct constexpr_ctx {
+  /* The innermost call we're evaluating.  */
   constexpr_call *call;
+  /* Values for any temporaries or local variables within the
+     constant-expression. */
   hash_map<tree,tree> *values;
+  /* The CONSTRUCTOR we're currently building up for an aggregate
+     initializer.  */
   tree ctor;
+  /* The object we're building the CONSTRUCTOR for.  */
   tree object;
+  /* Whether we should error on a non-constant expression or fail quietly.  */
   bool quiet;
+  /* Whether we are strictly conforming to constant expression rules or
+     trying harder to get a constant value.  */
   bool strict;
 };
 
@@ -3428,9 +3436,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 {
   bool non_constant_p = false;
   bool overflow_p = false;
-  constexpr_ctx ctx = { NULL, NULL, NULL, NULL, allow_non_constant, strict };
   hash_map<tree,tree> map;
-  ctx.values = &map;
+  constexpr_ctx ctx = { NULL, &map, NULL, NULL, allow_non_constant, strict };
   tree type = initialized_type (t);
   tree r = t;
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
@@ -3537,9 +3544,8 @@ is_sub_constant_expr (tree t)
 {
   bool non_constant_p = false;
   bool overflow_p = false;
-  constexpr_ctx ctx = { NULL, NULL, NULL, NULL, true, true };
   hash_map <tree, tree> map;
-  ctx.values = &map;
+  constexpr_ctx ctx = { NULL, &map, NULL, NULL, true, true };
   cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
 				&overflow_p);
   return !non_constant_p && !overflow_p;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]