diff mbox

[C++] Fix up cxx_eval_pointer_plus_expression (PR c++/65736)

Message ID 20150411140230.GD19273@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek April 11, 2015, 2:02 p.m. UTC
Hi!

The following patch fixes a bunch of issues in
cxx_eval_pointer_plus_expression:
1) as it does STRIP_NOPS, the pointed type can change, and thus the
   op01 constant in p+ might not be divisible by the other type size
2) we should restore the original type, rather than returning expression
   of type after STRIP_NOPS
3) just in case, I've added a check TYPE_SIZE_UNIT is a constant

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2015-04-11  Jakub Jelinek  <jakub@redhat.com>

	PR c++/65736
	* constexpr.c (cxx_eval_pointer_plus_expression): Don't fold for VLAs,
	don't fold if op01 isn't divisible by TYPE_SIZE_UNIT.  Convert
	the expression to the original type at the end.

	* g++.dg/cpp0x/pr65736.C: New test.


	Jakub

Comments

Jason Merrill April 12, 2015, 6:27 p.m. UTC | #1
OK.

Jason
diff mbox

Patch

--- gcc/cp/constexpr.c.jj	2015-04-03 15:32:31.000000000 +0200
+++ gcc/cp/constexpr.c	2015-04-11 10:28:12.154482385 +0200
@@ -2929,6 +2929,7 @@  cxx_eval_pointer_plus_expression (const
 				  bool lval, bool *non_constant_p,
 				  bool *overflow_p)
 {
+  tree orig_type = TREE_TYPE (t);
   tree op00 = TREE_OPERAND (t, 0);
   tree op01 = TREE_OPERAND (t, 1);
   location_t loc = EXPR_LOCATION (t);
@@ -2945,7 +2946,9 @@  cxx_eval_pointer_plus_expression (const
   /* &A[i] p+ j => &A[i + j] */
   if (TREE_CODE (op00) == ARRAY_REF
       && TREE_CODE (TREE_OPERAND (op00, 1)) == INTEGER_CST
-      && TREE_CODE (op01) == INTEGER_CST)
+      && TREE_CODE (op01) == INTEGER_CST
+      && TYPE_SIZE_UNIT (TREE_TYPE (op00))
+      && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (op00))) == INTEGER_CST)
     {
       tree type = TREE_TYPE (op00);
       t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (op00, 1));
@@ -2953,15 +2956,21 @@  cxx_eval_pointer_plus_expression (const
       /* Don't fold an out-of-bound access.  */
       if (!tree_int_cst_le (t, nelts))
 	return NULL_TREE;
+      op01 = cp_fold_convert (ssizetype, op01);
+      /* Don't fold if op01 can't be divided exactly by TYPE_SIZE_UNIT.
+	 constexpr int A[1]; ... (char *)&A[0] + 1 */
+      if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype,
+					   op01, TYPE_SIZE_UNIT (type))))
+	return NULL_TREE;
       /* Make sure to treat the second operand of POINTER_PLUS_EXPR
 	 as signed.  */
-      op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype,
-			      cp_fold_convert (ssizetype, op01),
+      op01 = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, op01,
 			      TYPE_SIZE_UNIT (type));
       t = size_binop_loc (loc, PLUS_EXPR, op01, t);
       t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (op00, 0),
 		      t, NULL_TREE, NULL_TREE);
       t = cp_build_addr_expr (t, tf_warning_or_error);
+      t = cp_fold_convert (orig_type, t);
       return cxx_eval_constant_expression (ctx, t, lval, non_constant_p,
 					   overflow_p);
     }
--- gcc/testsuite/g++.dg/cpp0x/pr65736.C.jj	2015-04-11 10:32:06.807729783 +0200
+++ gcc/testsuite/g++.dg/cpp0x/pr65736.C	2015-04-11 10:31:11.000000000 +0200
@@ -0,0 +1,5 @@ 
+// PR c++/65736
+// { dg-do compile { target c++11 } }
+
+int a[1];                                                                                                                                 
+char *b[1] { (char *)&a[0] + 1 };