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]

[PATCH] c++/67376 Comparison with pointer to past-the-end, of array fails inside constant expression


The attached patch fixes the outstanding cases mentioned in comment
10 on bug c++/67376.  While testing the fix I uncovered a number of
other related problems without which the test would have been
incomplete.  They include:

PR c++/70170 - [6 regression] bogus not a constant expression error
    comparing pointer to array to null
PR c++/70172 - incorrect reinterpret_cast from integer to pointer
    error on invalid constexpr initialization
PR c++/60760 - arithmetic on null pointers should not be allowed
    in constant expressions

In addition, I include a fix for the issue below that I also came
across while testing the patch and that makes root causing constexpr
problems due to out-of-bounds array subscripts easier:
PR c++/70228 - insufficient detail in diagnostics for a constexpr
    out of bounds array subscript

In a discussion of bug 70170 between those CC'd Marek posted
a prototype patch for match.pd.  While the patch seems to do
the right thing as far as the bug goes, like my own first attempt
at a fix in const-fold.c it caused a couple of regressions (in
pr21294.c and in pr44555.c).  Since I'm not yet familiar enough
with match.pd, in the interest of time I solved those regressions
in const-fold.c rather than in match.pd.

Tested on x86_64.

Martin
PR c++/67376 - [5/6 regression] Comparison with pointer to past-the-end
	of array fails inside constant expression
PR c++/70170 - [6 regression] bogus not a constant expression error comparing
	pointer to array to null
PR c++/70172 - incorrect reinterpret_cast from integer to pointer error
	on invalid constexpr initialization
PR c++/60760 - arithmetic on null pointers should not be allowed in constant
	expressions
PR c++/70228 - insufficient detail in diagnostics for a constexpr out of bounds
	array subscript

gcc/testsuite/ChangeLog:
2016-03-14  Martin Sebor  <msebor@redhat.com>

	PR c++/67376
	PR c++/70170
	PR c++/70172
	PR c++/60760
	PR c++/70228
	* g++.dg/cpp0x/constexpr-array-ptr10.C: New test.
	* g++.dg/cpp0x/constexpr-array-ptr11.C: New test.
	* g++.dg/cpp0x/constexpr-array-ptr9.C: New test.
	* g++.dg/cpp0x/constexpr-array5.C: Adjust text of expected diagnostic.
	* g++.dg/cpp0x/constexpr-string.C: Same.
	* g++.dg/cpp0x/constexpr-wstring2.C: Same.
	* g++.dg/cpp0x/pr65398.C: Same.
	* g++.dg/ext/constexpr-vla1.C: Same.
	* g++.dg/ext/constexpr-vla2.C: Same.
	* g++.dg/ext/constexpr-vla3.C: Same.
	* g++.dg/ubsan/pr63956.C: Same.

gcc/cp/ChangeLog:
2016-03-14  Martin Sebor  <msebor@redhat.com>

	PR c++/67376
	PR c++/70170
	PR c++/70172
	PR c++/60760
	PR c++/70228
	(cxx_eval_binary_expression): Add argument.
	(cxx_eval_component_reference): Same.
	(cxx_eval_constant_expression): Same.
	(cxx_eval_indirect_ref): Same.
	(cxx_eval_outermost_constant_expr): Same.
	(diag_array_subscript): New function.
	* constexpr.c (cxx_eval_call_expression): Adjust.
	(cxx_eval_conditional_expression): Same.
	(cxx_eval_array_reference): Detect null pointers.
	(cxx_eval_statement_list): Adjust.

gcc/ChangeLog:
2016-03-14  Martin Sebor  <msebor@redhat.com>

	PR c++/67376
	* fold-const.c (fold_comparison): Fold equality and relational
	expressions involving null pointers.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 5f97c9d..5ec5034 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -918,7 +918,8 @@ struct constexpr_ctx {
 static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
 
 static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
-					  bool, bool *, bool *, tree * = NULL);
+					  bool, bool *, bool *, bool * = NULL,
+                                          tree * = NULL);
 
 /* Compute a hash value for a constexpr call representation.  */
 
@@ -1390,7 +1391,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
 	  tree jump_target = NULL_TREE;
 	  cxx_eval_constant_expression (ctx, body,
 					lval, non_constant_p, overflow_p,
-					&jump_target);
+                                        NULL, &jump_target);
 
 	  if (DECL_CONSTRUCTOR_P (fun))
 	    /* This can be null for a subobject constructor call, in
@@ -1607,20 +1608,21 @@ 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 *non_constant_p, bool *overflow_p)
+			    bool *non_constant_p, bool *overflow_p,
+                            bool *nullptr_p)
 {
   tree r = NULL_TREE;
   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*/false,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, nullptr_p);
   /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer
      subtraction.  */
   if (*non_constant_p)
     return t;
   rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, nullptr_p);
   if (*non_constant_p)
     return t;
 
@@ -1642,6 +1644,15 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 		   || null_member_pointer_value_p (rhs)))
 	r = constant_boolean_node (!is_code_eq, type);
     }
+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+      && tree_int_cst_equal (lhs, null_pointer_node))
+    {
+      if (!ctx->quiet)
+        error ("arithmetic involving null pointer %qE", lhs);
+      if (nullptr_p)
+        *nullptr_p = true;
+      return t;
+    }
 
   if (r == NULL_TREE)
     r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -1682,11 +1693,11 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
     return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
 					 lval,
 					 non_constant_p, overflow_p,
-					 jump_target);
+					 NULL, jump_target);
   return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 				       lval,
 				       non_constant_p, overflow_p,
-				       jump_target);
+				       NULL, jump_target);
 }
 
 /* Returns less than, equal to, or greater than zero if KEY is found to be
@@ -1815,6 +1826,30 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert = false)
   return -1;
 }
 
+/* Under the control of CTX, issue a detailed diagnostic for
+   an out-of-bounds subscript INDEX into the expression ARRAY.  */
+
+static void
+diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index)
+{
+  if (!ctx->quiet)
+    {
+      tree arraytype = TREE_TYPE (array);
+
+      /* Convert the unsigned array subscript to a signed integer to avoid
+         printing huge numbers for small negative values.  */
+      tree sidx = fold_convert (ssizetype, index);
+      if (DECL_P (array))
+        {
+          error ("array subscript value %qE is outside the bounds "
+                 "of array %qD of type %qT", sidx, array, arraytype);
+          inform (DECL_SOURCE_LOCATION (array), "declared here");
+        }
+      else
+        error ("array subscript value %qE is outside the bounds "
+               "of array type %qT", sidx, arraytype);
+    }
+}
 
 /* Subroutine of cxx_eval_constant_expression.
    Attempt to reduce a reference to an array slot.  */
@@ -1839,11 +1874,26 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 					false,
 					non_constant_p, overflow_p);
   VERIFY_CONSTANT (index);
+
+  tree arytype = TREE_TYPE (ary);
+  tree nelts = array_type_nelts_top (arytype);
+  /* For VLAs, the number of elements won't be an integer constant.  */
+  nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
+					overflow_p);
+  VERIFY_CONSTANT (nelts);
+
+  if (tree_int_cst_lt (nelts, index))
+    {
+      diag_array_subscript (ctx, ary, index);
+      *non_constant_p = true;
+      return t;
+    }
+
   if (lval && ary == oldary && index == oldidx)
     return t;
   else if (lval)
     return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
-  elem_type = TREE_TYPE (TREE_TYPE (ary));
+  elem_type = TREE_TYPE (arytype);
   if (TREE_CODE (ary) == CONSTRUCTOR)
     len = CONSTRUCTOR_NELTS (ary);
   else if (TREE_CODE (ary) == STRING_CST)
@@ -1863,21 +1913,14 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
   if (!tree_fits_shwi_p (index)
       || (i = tree_to_shwi (index)) < 0)
     {
-      if (!ctx->quiet)
-	error ("negative array subscript");
+      diag_array_subscript (ctx, ary, index);
       *non_constant_p = true;
       return t;
     }
 
-  tree nelts = array_type_nelts_top (TREE_TYPE (ary));
-  /* For VLAs, the number of elements won't be an integer constant.  */
-  nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
-					overflow_p);
-  VERIFY_CONSTANT (nelts);
   if (!tree_int_cst_lt (index, nelts))
     {
-      if (!ctx->quiet)
-	error ("array subscript out of bound");
+      diag_array_subscript (ctx, ary, index);
       *non_constant_p = true;
       return t;
     }
@@ -1935,7 +1978,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
 static tree
 cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
 			      bool lval,
-			      bool *non_constant_p, bool *overflow_p)
+			      bool *non_constant_p, bool *overflow_p,
+                              bool *nullptr_p)
 {
   unsigned HOST_WIDE_INT i;
   tree field;
@@ -1944,7 +1988,14 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree orig_whole = TREE_OPERAND (t, 0);
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 					     lval,
-					     non_constant_p, overflow_p);
+					     non_constant_p, overflow_p,
+                                             nullptr_p);
+  if (nullptr_p && *nullptr_p)
+    {
+      if (!ctx->quiet)
+        error ("%qE dereferences a null pointer", orig_whole);
+    }
+
   if (TREE_CODE (whole) == PTRMEM_CST)
     whole = cplus_expand_constant (whole);
   if (whole == orig_whole)
@@ -2655,7 +2706,8 @@ 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 lval,
-		       bool *non_constant_p, bool *overflow_p)
+		       bool *non_constant_p, bool *overflow_p,
+                       bool *nullptr_p)
 {
   tree orig_op0 = TREE_OPERAND (t, 0);
   bool empty_base = false;
@@ -2680,6 +2732,9 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
       tree op0 = cxx_eval_constant_expression (ctx, orig_op0,
 					       /*lval*/false, non_constant_p,
 					       overflow_p);
+      if (nullptr_p && tree_int_cst_equal (op0, null_pointer_node))
+        *nullptr_p = true;
+
       /* Don't VERIFY_CONSTANT here.  */
       if (*non_constant_p)
 	return t;
@@ -3149,7 +3204,7 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t,
 	}
       r = cxx_eval_constant_expression (ctx, stmt, false,
 					non_constant_p, overflow_p,
-					jump_target);
+					NULL, jump_target);
       if (*non_constant_p)
 	break;
       if (returns (jump_target) || breaks (jump_target))
@@ -3285,8 +3340,10 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
 static tree
 cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 			      bool lval,
-			      bool *non_constant_p, bool *overflow_p,
-			      tree *jump_target)
+			      bool *non_constant_p,
+                              bool *overflow_p,
+                              bool *nullptr_p,
+                              tree *jump_target)
 {
   constexpr_ctx new_ctx;
   tree r = t;
@@ -3300,10 +3357,21 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     {
       if (TREE_OVERFLOW (t) && (!flag_permissive || ctx->quiet))
 	*overflow_p = true;
+
+      if (TREE_CODE (t) == INTEGER_CST
+          && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+          && !integer_zerop (t))
+        {
+          if (!ctx->quiet)
+            error ("null pointer arithmetic in %qE", t);
+          if (nullptr_p)
+            *nullptr_p = true;
+        }
       return t;
     }
 
-  switch (TREE_CODE (t))
+  tree_code tcode = TREE_CODE (t);
+  switch (tcode)
     {
     case RESULT_DECL:
       if (lval)
@@ -3392,7 +3460,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  {
 	    init = cxx_eval_constant_expression (ctx, init,
 						 false,
-						 non_constant_p, overflow_p);
+						 non_constant_p, overflow_p,
+                                                 nullptr_p);
 	    /* Don't share a CONSTRUCTOR that might be changed.  */
 	    init = unshare_expr (init);
 	    ctx->values->put (r, init);
@@ -3432,7 +3501,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	 initialization of a temporary.  */
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					false,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p,
+                                        nullptr_p);
       if (!*non_constant_p)
 	/* Adjust the type of the result to the type of the temporary.  */
 	r = adjust_temp_type (TREE_TYPE (t), r);
@@ -3454,14 +3524,16 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case SCOPE_REF:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
 					lval,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p,
+                                        nullptr_p);
       break;
 
     case RETURN_EXPR:
       if (TREE_OPERAND (t, 0) != NULL_TREE)
 	r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
 					  lval,
-					  non_constant_p, overflow_p);
+					  non_constant_p, overflow_p,
+                                          nullptr_p);
       *jump_target = t;
       break;
 
@@ -3472,7 +3544,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       else
 	{
 	  r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false,
-					    non_constant_p, overflow_p);
+					    non_constant_p, overflow_p,
+                                            nullptr_p);
 	  ctx->values->put (t, r);
 	  if (ctx->save_exprs)
 	    ctx->save_exprs->add (t);
@@ -3489,18 +3562,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
 					lval,
 					non_constant_p, overflow_p,
-					jump_target);
+                                        nullptr_p, jump_target);
       break;
 
     case TRY_FINALLY_EXPR:
       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
 					non_constant_p, overflow_p,
-					jump_target);
+					nullptr_p, jump_target);
       if (!*non_constant_p)
 	/* Also evaluate the cleanup.  */
 	cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true,
 				      non_constant_p, overflow_p,
-				      jump_target);
+				      nullptr_p, jump_target);
       break;
 
       /* These differ from cxx_eval_unary_expression in that this doesn't
@@ -3509,7 +3582,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case MEM_REF:
     case INDIRECT_REF:
       r = cxx_eval_indirect_ref (ctx, t, lval,
-				 non_constant_p, overflow_p);
+				 non_constant_p, overflow_p, nullptr_p);
       break;
 
     case ADDR_EXPR:
@@ -3517,7 +3590,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	tree oldop = TREE_OPERAND (t, 0);
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						/*lval*/true,
-						non_constant_p, overflow_p);
+						non_constant_p, overflow_p,
+                                                nullptr_p);
 	/* Don't VERIFY_CONSTANT here.  */
 	if (*non_constant_p)
 	  return t;
@@ -3560,17 +3634,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	    || TREE_CODE (op1) == EMPTY_CLASS_EXPR)
 	  r = cxx_eval_constant_expression (ctx, op0,
 					    lval, non_constant_p, overflow_p,
-					    jump_target);
+                                            nullptr_p, jump_target);
 	else
 	  {
 	    /* Check that the LHS is constant and then discard it.  */
 	    cxx_eval_constant_expression (ctx, op0,
 					  true, non_constant_p, overflow_p,
-					  jump_target);
+					  nullptr_p, jump_target);
 	    op1 = TREE_OPERAND (t, 1);
 	    r = cxx_eval_constant_expression (ctx, op1,
 					      lval, non_constant_p, overflow_p,
-					      jump_target);
+					      nullptr_p, jump_target);
 	  }
       }
       break;
@@ -3621,7 +3695,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case RANGE_EXPR:
     case COMPLEX_EXPR:
       r = cxx_eval_binary_expression (ctx, t, lval,
-				      non_constant_p, overflow_p);
+				      non_constant_p, overflow_p, nullptr_p);
       break;
 
       /* fold can introduce non-IF versions of these; still treat them as
@@ -3659,7 +3733,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  return t;
 	}
       r = cxx_eval_component_reference (ctx, t, lval,
-					non_constant_p, overflow_p);
+					non_constant_p, overflow_p, nullptr_p);
       break;
 
     case BIT_FIELD_REF:
@@ -3712,12 +3786,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case NOP_EXPR:
     case UNARY_PLUS_EXPR:
       {
-	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
 
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						lval,
-						non_constant_p, overflow_p);
+						non_constant_p, overflow_p,
+                                                nullptr_p);
 	if (*non_constant_p)
 	  return t;
 	tree type = TREE_TYPE (t);
@@ -3738,15 +3812,28 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 		return t;
 	      }
 	  }
-	if (POINTER_TYPE_P (type)
-	    && TREE_CODE (op) == INTEGER_CST
-	    && !integer_zerop (op))
-	  {
-	    if (!ctx->quiet)
-	      error_at (EXPR_LOC_OR_LOC (t, input_location),
-			"reinterpret_cast from integer to pointer");
-	    *non_constant_p = true;
-	    return t;
+	if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
+          {
+            const char *msg = NULL;
+            if (integer_zerop (op))
+              {
+                if (nullptr_p)
+                  *nullptr_p = true;
+                if (!same_type_ignoring_top_level_qualifiers_p (type,
+                                                                TREE_TYPE (op)))
+                  msg = "invalid conversion involving a null pointer";
+              }
+            else
+              msg = "reinterpret_cast from integer to pointer";
+
+            if (msg)
+              {
+                if (!ctx->quiet)
+                  error_at (EXPR_LOC_OR_LOC (t, input_location), msg);
+
+                *non_constant_p = true;
+                return t;
+              }
 	  }
 	if (op == oldop && tcode != UNARY_PLUS_EXPR)
 	  /* We didn't fold at the top so we could check for ptr-int
@@ -3779,7 +3866,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return cxx_eval_constant_expression (ctx, BIND_EXPR_BODY (t),
 					   lval,
 					   non_constant_p, overflow_p,
-					   jump_target);
+					   nullptr_p, jump_target);
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -3828,7 +3915,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  tree ctor = lval ? ctx->object : ctx->ctor;
 	  return cxx_eval_constant_expression
 	    (ctx, ctor, lval,
-	     non_constant_p, overflow_p);
+	     non_constant_p, overflow_p, nullptr_p);
 	}
       break;
 
@@ -3935,8 +4022,9 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 	r = TARGET_EXPR_INITIAL (r);
     }
 
-  r = cxx_eval_constant_expression (&ctx, r,
-				    false, &non_constant_p, &overflow_p);
+  bool nullptr_p = false;
+  r = cxx_eval_constant_expression (&ctx, r, false,
+                                    &non_constant_p, &overflow_p, &nullptr_p);
 
   verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 696b4a6..376aa09 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -8639,6 +8639,37 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
 	    base1 = build_fold_addr_expr_loc (loc, base1);
 	  return fold_build2_loc (loc, code, type, base0, base1);
 	}
+
+      /* Comparison between an ordinary (non-weak) symbol and a null
+	 pointer can be eliminated since such sybols must have a non
+	 null address.  */
+      else if (DECL_P (base0)
+               && (!HAS_DECL_ASSEMBLER_NAME_P (base0) || !DECL_WEAK (base0))
+	       /* Avoid folding references to struct members at offset 0 to
+		  prevent tests like '&ptr->firstmember == 0' from getting
+		  eliminated.  When ptr is null, although the -> expression
+		  is strictly speaking invalid, GCC retains it as a matter
+		  of QoI.  See PR c/44555. */
+	       && (TREE_CODE (op0) != ADDR_EXPR
+		   || TREE_CODE (TREE_OPERAND (op0, 0)) != COMPONENT_REF
+		   || compare_tree_int (DECL_FIELD_OFFSET ((TREE_OPERAND
+				           (TREE_OPERAND (op0, 0), 1))), 0))
+	       && TREE_CODE (arg1) == INTEGER_CST
+               && compare_tree_int (arg1, 0) == 0)
+	{
+	  switch (code)
+	    {
+	    case GE_EXPR:
+	    case EQ_EXPR:
+	    case LE_EXPR:
+	      return boolean_false_node;
+	    case GT_EXPR:
+	    case LT_EXPR:
+	    case NE_EXPR:
+	      return boolean_true_node;
+	    default: gcc_unreachable ();
+	    }
+	}
     }
 
   /* Transform comparisons of the form X +- C1 CMP Y +- C2 to
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
new file mode 100644
index 0000000..b3b68ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
@@ -0,0 +1,150 @@
+// PR c++/67376 - [5/6 regression] Comparison with pointer to past-the-end
+//                of array fails inside constant expression
+// This test verifies the aspect of the bug raised in comment #10,
+// specifically comparing pointers to null.  The basic regression test
+// is in g++.dg/cpp0x/constexpr-67376.C.
+// Note also that while the description of the bug talks about pointers
+// pointing past the end of arrays but the prolem is more general than
+// that and involves all constexpr object pointers.
+
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wall -Wno-extra" }
+
+namespace A {
+
+extern int i;
+
+constexpr int *p0 = &i;
+
+constexpr bool b0  = p0;        // { dg-warning "address of .A::i. will always evaluate as .true." }
+
+// The following don't cause the -Waddress warning due to bug c++/70194.
+constexpr bool b1  = p0 == 0;
+constexpr bool b2  = p0 != 0;
+constexpr bool b3  = p0 <  0;
+constexpr bool b4  = p0 <= 0;
+constexpr bool b5  = p0 >  0;
+constexpr bool b6  = p0 >= 0;
+
+constexpr bool b7  = !p0;       // { dg-warning "address of .A::i. will always evaluate as .true." }
+
+// The following don't cause the -Waddress warning due to bug c++/70194.
+constexpr bool b8  = 0 == p0;
+constexpr bool b9  = 0 != p0;
+constexpr bool b10 = 0 <  p0;
+constexpr bool b11 = 0 <= p0;
+constexpr bool b12 = 0 >  p0;
+constexpr bool b13 = 0 >= p0;
+
+}
+
+namespace B {
+
+// PR c++/70170 - [6 regression] bogus not a constant expression error
+// comparing pointer to array to null
+// PR c++/70172 - incorrect reinterpret_cast from integer to pointer
+// error on invalid constexpr initialization
+
+struct S { int a, b[1]; } s;
+
+constexpr S *p0 = &s;
+constexpr S *p1 = nullptr;
+
+constexpr int *q0 = p0->b;      // { dg-bogus "reinterpret_cast from integer to pointer" }
+constexpr int *r0 = p1->b;      // { dg-error "null pointer|constant expression" }
+
+constexpr bool b0  = p0;        // { dg-warning "address of .B::s. will always evaluate as .true." }
+
+// The following don't cause the -Waddress warning due to bug c++/70194.
+constexpr bool b1  = p0 == 0;
+constexpr bool b2  = p0 != 0;
+constexpr bool b3  = p0 <  0;
+constexpr bool b4  = p0 <= 0;
+constexpr bool b5  = p0 >  0;
+constexpr bool b6  = p0 >= 0;
+
+constexpr bool b7  = !p0;       // { dg-warning "address of .B::s. will always evaluate as .true." }
+
+// The following don't cause the -Waddress warning due to bug c++/70194.
+constexpr bool b8  = 0 == p0;
+constexpr bool b9  = 0 != p0;
+constexpr bool b10 = 0 <  p0;
+constexpr bool b11 = 0 <= p0;
+constexpr bool b12 = 0 >  p0;
+constexpr bool b13 = 0 >= p0;
+
+}
+
+namespace C {
+
+struct A { int i; const A *pa1; const A *pa0; };
+
+constexpr A a1 = { 0, 0, 0  };
+constexpr A a2 = { 1, &a1, 0 };
+
+constexpr const A *pa2 = &a2;
+constexpr int i0 = pa2->i;
+constexpr int i1 = pa2->pa1->i;
+constexpr int i2 = pa2->pa1->pa0->i;           // { dg-error "null pointer|not a constant" }
+
+constexpr const A *pa3 = &*pa2->pa1->pa0;
+constexpr const A *pa4 = pa2->pa1->pa0 + 1;    // { dg-error "null pointer|not a constant" }
+
+constexpr const int *pi0 = &pa2->pa1->pa0->i;  // { dg-error "null pointer|not a constant" }
+
+constexpr const A *pa5 = 0;
+constexpr const int *pi1 = &pa5->i;            // { dg-error "null pointer|not a constant" }
+
+}
+
+namespace WeakRefTest1 {
+
+extern __attribute__ ((weak)) int i;
+
+constexpr int *p0 = &i;
+
+constexpr bool b0  = p0;        // { dg-error "not a constant expression" }
+constexpr bool b1  = p0 == 0;   // { dg-error "not a constant expression" }
+constexpr bool b2  = p0 != 0;   // { dg-error "not a constant expression" }
+constexpr bool b4  = p0 <= 0;   // { dg-error "not a constant expression" }
+constexpr bool b5  = p0 >  0;   // { dg-error "not a constant expression" }
+
+constexpr bool b7  = !p0;       // { dg-error "not a constant expression" }
+constexpr bool b8  = 0 == p0;   // { dg-error "not a constant expression" }
+constexpr bool b9  = 0 != p0;   // { dg-error "not a constant expression" }
+constexpr bool b10 = 0 <  p0;   // { dg-error "not a constant expression" }
+constexpr bool b13 = 0 >= p0;   // { dg-error "not a constant expression" }
+
+// The following are accepted as constant expressions due to bug c++/70196.
+constexpr bool b3  = p0 <  0;
+constexpr bool b6  = p0 >= 0;
+constexpr bool b11 = 0 <= p0;
+constexpr bool b12 = 0 >  p0;
+
+}
+
+namespace WeakRefTest2 {
+
+extern __attribute__ ((weak)) int i;
+
+constexpr int *p1 = &i + 1;
+
+constexpr bool b0  = p1;        // { dg-error "not a constant expression" }
+constexpr bool b1  = p1 == 0;   // { dg-error "not a constant expression" }
+constexpr bool b2  = p1 != 0;   // { dg-error "not a constant expression" }
+constexpr bool b4  = p1 <= 0;   // { dg-error "not a constant expression" }
+constexpr bool b5  = p1 >  0;   // { dg-error "not a constant expression" }
+
+constexpr bool b7  = !p1;       // { dg-error "not a constant expression" }
+constexpr bool b8  = 0 == p1;   // { dg-error "not a constant expression" }
+constexpr bool b9  = 0 != p1;   // { dg-error "not a constant expression" }
+constexpr bool b10 = 0 <  p1;   // { dg-error "not a constant expression" }
+constexpr bool b13 = 0 >= p1;   // { dg-error "not a constant expression" }
+
+// The following are accepted as constant expressions due to bug c++/70196.
+// constexpr bool b3  = p1 <  0;   
+// constexpr bool b6  = p1 >= 0;
+// constexpr bool b11 = 0 <= p1;
+// constexpr bool b12 = 0 >  p1;
+
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr11.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr11.C
new file mode 100644
index 0000000..3b28f20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr11.C
@@ -0,0 +1,128 @@
+// PR c++/60760 - arithmetic on null pointers should not be allowed
+//     in constant expressions
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-pointer-arith" }
+
+// Generate a null poiinter.
+constexpr int* null () { return 0; }
+
+namespace SimpleTests {
+
+constexpr int* p0 = nullptr;
+constexpr int* q0 = p0;
+constexpr int* r0 = null ();
+
+// Adding or subtracting zero from a null pointer is valid in C++.
+constexpr int* p1 = p0 + 0;
+constexpr int* p2 = p0 - 0;
+constexpr int* p3 = 0 + p0;
+
+// While the text of the C++ standard still doesn't allow it, CWG
+// issue 232 implies that dererencing a null pointer is intended
+// to be permitted in contexts where the result isn't evaluated.
+// For compatibility with C that should at a minimum include
+// expressions like &*p that are valid there.
+constexpr int* p4 = &*p0;
+constexpr int* p5 = p0 + 1;       // { dg-error "null pointer|not a constant" }
+constexpr int* p6 = 1 + p0;       // { dg-error "null pointer|not a constant" }
+constexpr int* p7 = p0 - 1;       // { dg-error "null pointer|not a constant" }
+constexpr int* p8 = &p0 [0];
+constexpr int* p9 = &0 [p0];
+
+constexpr int* p10 = null () + 2; // { dg-error "null pointer|not a constant" }
+constexpr int* p11 = 3 + null (); // { dg-error "null pointer|not a constant" }
+constexpr int* p12 = null () - 4; // { dg-error "null pointer|not a constant" }
+constexpr int* p13 = &null ()[4]; // { dg-error "null pointer|not a constant" }
+constexpr int* p14 = &3[null ()]; // { dg-error "null pointer|not a constant" }
+
+constexpr int* q1 = q0 + 0;
+constexpr int* q2 = q0 - 0;
+constexpr int* q3 = q0 + 1;       // { dg-error "null pointer|not a constant" }
+constexpr int* q4 = q0 + 2;       // { dg-error "null pointer|not a constant" }
+constexpr int* q5 = &q0 [0];
+
+// Subtracting null pointers from one another is valid.
+constexpr int i0 = p0 - (int*)0;
+constexpr int i1 = p0 - static_cast<int*>(0);
+constexpr int i2 = p0 - (int*)nullptr;
+constexpr int i3 = p0 - static_cast<int*>(nullptr);
+constexpr int i4 = p0 - p0;
+constexpr int i5 = p0 - q0;
+constexpr int i6 = p0 - r0;
+constexpr int i7 = (int*)0 - p0;
+constexpr int i8 = static_cast<int*>(0) - p0;
+constexpr int i9 = (int*)nullptr - p0;
+constexpr int i10 = static_cast<int*>(nullptr) - p0;
+constexpr int i11 = q0 - p0;
+constexpr int i12 = r0 - p0;
+
+}
+
+namespace IndirectTests {
+
+struct S { int i, j; struct SA { struct SB { int *pi; } sb; } sa; };
+
+constexpr S* ps = (S*)0;
+
+// Comparing null pointers is valid.
+constexpr bool b0 = ps == ps;
+constexpr bool b1 = ps != ps;
+constexpr bool b2 = ps <  ps;
+constexpr bool b3 = ps <= ps;
+constexpr bool b4 = ps >  ps;
+constexpr bool b5 = ps >= ps;
+
+constexpr bool b6 = ps == (S*)0;
+constexpr bool b7 = ps != (S*)0;
+constexpr bool b8 = ps <  (S*)0;
+constexpr bool b9 = ps <= (S*)0;
+constexpr bool b10 = ps >  (S*)0;
+constexpr bool b11 = ps >= (S*)0;
+
+constexpr S* ps1 = ps;
+constexpr S* ps2 = ps1;
+
+// The following aren't diagnosed due to a bug.
+// constexpr int* pi0 = &((S*)0)->i;
+// constexpr int* pi1 = &((S*)nullptr)->i;
+
+constexpr int* pj0 = &((S*)0)->j;        // { dg-error "null pointer|not a constant" }
+constexpr int* pj1 = &((S*)nullptr)->j;  // { dg-error "null pointer|not a constant" }
+
+constexpr int* psi = &ps->i;            // { dg-error "null pointer|not a constant" }
+constexpr int* psj = &ps->j;            // { dg-error "null pointer|not a constant" }
+
+constexpr int* ps1i = &ps1->i;          // { dg-error "null pointer|not a constant" }
+constexpr int* ps2i = &ps1->i;          // { dg-error "null pointer|not a constant" }
+
+constexpr int* ps1j = &ps1->j;          // { dg-error "null pointer|not a constant" }
+constexpr int* ps2j = &ps1->j;          // { dg-error "null pointer|not a constant" }
+
+}
+
+namespace FunctionTests {
+
+typedef void Func ();
+
+// Arithmetic on member function pointers is diagnosed with -Wpointer-arith.
+// With constexpr, only zero may be added or subtracted.
+constexpr Func *pf0 = 0;
+constexpr Func *pf1 = pf0 + 0;  // triggers -Wpointer-arith
+constexpr Func *pf2 = pf0 - 0;  // triggers -Wpointer-arith
+constexpr Func *pf3 = 0 + pf0;  // triggers -Wpointer-arith
+constexpr Func *pf4 = pf0 + 1;  // { dg-error "null pointer|not a constant" }
+constexpr Func *pf5 = 2 + pf0;  // { dg-error "null pointer|not a constant" }
+constexpr Func *pf6 = pf0 - 3;  // { dg-error "null pointer|not a constant" }
+
+struct S;
+typedef void (S::*MemFuncPtr)();
+
+// Arithmetic on member function pointers is rejected with a hard error.
+constexpr MemFuncPtr pmf0 = nullptr;
+constexpr MemFuncPtr pmf1 = pmf0 + 0;   // { dg-error "invalid operands" }
+constexpr MemFuncPtr pmf2 = 0 + pmf0;   // { dg-error "invalid operands" }
+constexpr MemFuncPtr pmf3 = pmf0 + 1;   // { dg-error "invalid operands" }
+constexpr MemFuncPtr pmf4 = 1 + pmf0;   // { dg-error "invalid operands" }
+constexpr MemFuncPtr pmf5 = pmf0 - 1;   // { dg-error "invalid operands" }
+
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C
new file mode 100644
index 0000000..c690131
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C
@@ -0,0 +1,56 @@
+// PR c++/67376
+// { dg-do compile { target c++11 } }
+
+int a [2];
+
+constexpr const int* pa[] = {
+  a,
+  a + 0,
+  a + 1,
+  a + 2,
+  &a [0],
+  &a [0] + 0,
+  &a [0] + 1,
+  &a [0] + 2,
+  &a [1],
+  &a [1] - 1,
+  &a [1] + 0,
+  &a [1] + 1,
+  &a [2] - 2,
+  &a [2] - 1,
+  &a [2] + 0
+};
+
+#define Assert(e) static_assert ((e), #e)
+
+Assert (!(a == 0));
+Assert (!(a == (int*)0));
+Assert (!(a == nullptr));
+
+Assert (a != 0);
+Assert (a != (int*)0);
+Assert (a != nullptr);
+
+Assert (!(0 == a));
+Assert (!((int*)0 == a));
+Assert (!(nullptr == a));
+
+Assert (0 != a);
+Assert ((int*)0 != a);
+Assert (nullptr != a);
+
+bool constexpr test_eq (unsigned inx)
+{
+  return inx ? pa [inx - 1] == 0 && 0 == pa [inx - 1]
+    && test_eq (inx - 1) : pa [inx] == 0 && 0 == pa [inx];
+}
+
+Assert (!test_eq (sizeof pa / sizeof *pa));
+
+bool constexpr test_ne (unsigned inx)
+{
+  return inx ? pa [inx - 1] != 0 && 0 != pa [inx - 1]
+    && test_ne (inx - 1) : pa [inx] != 0 && 0 != pa [inx];
+}
+
+Assert (test_ne (sizeof pa / sizeof *pa));
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C
index 4605b4b..00dfd6d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C
@@ -3,7 +3,7 @@
 
 // Reliable ICE
 constexpr int n[3] = {};
-constexpr int k = n[-1];            // { dg-error "negative" }
+constexpr int k = n[-1];            // { dg-error "array subscript" }
 
 // Some random byte
-constexpr char c = "foo"[-1000];    // { dg-error "negative" }
+constexpr char c = "foo"[-1000];    // { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
index 0f561a4..41fa466 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
@@ -2,4 +2,4 @@
 
 constexpr char c1 = "hi"[1];
 constexpr char c2 = "hi"[2];
-constexpr char c3 = "hi"[3];	// { dg-error "out of bound" }
+constexpr char c3 = "hi"[3];	// { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
index db79a9c..4055e0e 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
@@ -1,6 +1,6 @@
 // PR c++/48570
 // { dg-do compile { target c++11 } }
 
-constexpr wchar_t c1 = L"hi"[3];	// { dg-error "out of bound" }
-constexpr char16_t c2 = u"hi"[3];	// { dg-error "out of bound" }
-constexpr char32_t c3 = U"hi"[3];	// { dg-error "out of bound" }
+constexpr wchar_t c1 = L"hi"[3];	// { dg-error "array subscript" }
+constexpr char16_t c2 = u"hi"[3];	// { dg-error "array subscript" }
+constexpr char32_t c3 = U"hi"[3];	// { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65398.C b/gcc/testsuite/g++.dg/cpp0x/pr65398.C
index a4aeba5..bab875c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65398.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65398.C
@@ -12,17 +12,17 @@ constexpr char c5 = *(&s[2] + 0);
 constexpr char c6 = *(&s[0] + 2);
 constexpr char c7 = *(&s[2] + 1);
 
-constexpr char d1 = *(&s[4] - 0); // { dg-error "array subscript out of bound" }
+constexpr char d1 = *(&s[4] - 0); // { dg-error "array subscript" }
 constexpr char d2 = *(&s[4] - 1);
 constexpr char d3 = *(&s[4] - 2);
 constexpr char d4 = *(&s[4] - 3);
 constexpr char d5 = *(&s[4] - 4);
-constexpr char d6 = *(&s[4] - 5);  // { dg-error "negative array subscript" }
+constexpr char d6 = *(&s[4] - 5);  // { dg-error "array subscript" }
 
 /* Don't accept invalid stuff.  */
-constexpr char e1 = *(&s[5] - 1); // { dg-error "is not a constant expression" }
-constexpr char e2 = *(&s[5] - 2); // { dg-error "is not a constant expression" }
-constexpr char e3 = *(&s[5] - 3); // { dg-error "is not a constant expression" }
+constexpr char e1 = *(&s[5] - 1); // { dg-error "array subscript" }
+constexpr char e2 = *(&s[5] - 2); // { dg-error "array subscript" }
+constexpr char e3 = *(&s[5] - 3); // { dg-error "array subscript" }
 
 SA (c1 == 'a');
 SA (c2 == 'b');
@@ -45,17 +45,17 @@ constexpr int i5 = *(&l[2] + 0);
 constexpr int i6 = *(&l[0] + 2);
 constexpr int i7 = *(&l[2] + 1);
 
-constexpr char j1 = *(&l[4] - 0); // { dg-error "array subscript out of bound" }
+constexpr char j1 = *(&l[4] - 0); // { dg-error "array subscript" }
 constexpr char j2 = *(&l[4] - 1);
 constexpr char j3 = *(&l[4] - 2);
 constexpr char j4 = *(&l[4] - 3);
 constexpr char j5 = *(&l[4] - 4);
-constexpr char j6 = *(&l[4] - 5);  // { dg-error "negative array subscript" }
+constexpr char j6 = *(&l[4] - 5);  // { dg-error "array subscript" }
 
 /* Don't accept invalid stuff.  */
-constexpr char k1 = *(&l[5] - 1); // { dg-error "is not a constant expression" }
-constexpr char k2 = *(&l[5] - 2); // { dg-error "is not a constant expression" }
-constexpr char k3 = *(&l[5] - 3); // { dg-error "is not a constant expression" }
+constexpr char k1 = *(&l[5] - 1); // { dg-error "array subscript" }
+constexpr char k2 = *(&l[5] - 2); // { dg-error "array subscript" }
+constexpr char k3 = *(&l[5] - 3); // { dg-error "array subscript" }
 
 SA (i1 == 'c');
 SA (i2 == 'd');
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla1.C b/gcc/testsuite/g++.dg/ext/constexpr-vla1.C
index a5615bb..21eb93d 100644
--- a/gcc/testsuite/g++.dg/ext/constexpr-vla1.C
+++ b/gcc/testsuite/g++.dg/ext/constexpr-vla1.C
@@ -27,4 +27,4 @@ fn_not_ok (int n)
 }
 
 constexpr int n1 = fn_ok (3);
-constexpr int n2 = fn_not_ok (3); // { dg-error "array subscript out of bound" }
+constexpr int n2 = fn_not_ok (3); // { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
index 6cb1f70..6aab184 100644
--- a/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
+++ b/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
@@ -18,4 +18,4 @@ fn_ok (int n)
 }
 
 constexpr int i1 = fn_ok (3);
-constexpr int i2 = fn_bad (3); // { dg-error "array subscript out of bound" }
+constexpr int i2 = fn_bad (3); // { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
index ba4eb50..33fc968 100644
--- a/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
+++ b/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
@@ -11,4 +11,4 @@ foo (int n)
   return z;
 }
 
-constexpr int n = foo (3); // { dg-error "array subscript out of bound" }
+constexpr int n = foo (3); // { dg-error "array subscript" }
diff --git a/gcc/testsuite/g++.dg/ubsan/pr63956.C b/gcc/testsuite/g++.dg/ubsan/pr63956.C
index b265631..98991fd 100644
--- a/gcc/testsuite/g++.dg/ubsan/pr63956.C
+++ b/gcc/testsuite/g++.dg/ubsan/pr63956.C
@@ -86,7 +86,7 @@ fn5 (const int *a, int b)
 
 constexpr int m1[4] = { 1, 2, 3, 4 };
 constexpr int m2 = fn5 (m1, 3);
-constexpr int m3 = fn5 (m1, 4); // { dg-error "array subscript out of bound" }
+constexpr int m3 = fn5 (m1, 4); // { dg-error "array subscript" }
 
 constexpr int
 fn6 (const int &a, int b)
@@ -106,7 +106,7 @@ fn7 (const int *a, int b)
 
 constexpr int n1 = 7;
 constexpr int n2 = fn7 (&n1, 5);
-constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-error "is not a constant expression" }
+constexpr int n3 = fn7 ((const int *) 0, 8); // { dg-error "null pointer" }
 
 constexpr int
 fn8 (int i)
@@ -116,7 +116,7 @@ fn8 (int i)
 }
 
 constexpr int o1 = fn8 (9);
-constexpr int o2 = fn8 (10); // { dg-error "array subscript out of bound" }
+constexpr int o2 = fn8 (10); // { dg-error "array subscript" }
 
 constexpr int
 fn9 (int a, int b)

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