static tree cxx_eval_constant_expression (const constexpr_ctx *, tree,
-                      bool, bool *, bool *, tree * = NULL);
+                      bool, bool *, bool *, bool * = NULL,
+                                          tree * = NULL);
I didn't look deeply, but do you end up fixing all (most) of the callers
of cxx_eval_constant_expression?  If so, then you don't need the default
initialization.

Thanks for the comments.  The patch only modifies about 10 out
of the 70 or so calls to the function in the file and the default
argument helps avoid making the rest of the changes.  (I have some
ideas for improving the APIs of these functions that I'd like to
run by Jason when we're done with the 6.0 work.)

At a high level, I'm curious your thoughts on emitting these errors out
of the front-end rather than after analysis.  I'm thinking in particular
about constant propagation,  unreachable code elimination and DCE.  The
former can expose cases that are difficult to catch in the front-end,
while the latter two might remove an out-of-range comparison/reference.

The difficulty I've run into with detecting these problems in later
phases is that some invalid expressions have already been simplified
by the front end.  The example that applies here (even though this
is still the front end) is this:

  constexpr int* p = 0;
  constexpr bool b0 = &p[0] == 0;   // accepted
  constexpr bool b1 = &p[1] == 0;   // rejected

Both b0 and b1 are invalid and should be diagnosed, but only b1
is.  b1 isn't because because by the time we see its initializer
in constexpr.c it's been transformed into the equivalent of "b1
= (int*)ps" (though we don't see the cast which would also make
it invalid).

But if we can avoid these early simplifying transformations and
retain a more faithful representation of the original source then
doing the checking later will likely be simpler and result in
detecting more problems with greater consistency and less effort.

  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.  */
Hmm, I thought we already had code to do this somewhere.   It looks like
it's moved around quite a bit.  I think you want to be using
symtab_node::nonzero_address to determine if a given symbol must bind to
a nonzero address.

Thanks for the hint.  I had looked for existing functions but
couldn't find one that worked.  decl_with_nonnull_addr_p() in
c-common.c looked promising but it's not accessible here and
it doesn't do the right thing when HAS_DECL_ASSEMBLER_NAME_P()
is false (it ICEs).

There are a few functions in the fold-const.c itself that make
use of symtab_node::nonzero_address(), either directly or
indirectly (tree_expr_nonzero_p and tree_expr_nonzero_warnv_p)
but none is usable in this context (they don't handle VAR_DECL,
and adding that handling appears more involved than the current
approach).

In the end, I added a new function, maybe_nonzero_address(),
that calls symtab_node::nonzero_address(), and that I factored
out of tree_single_nonzero_warnv_p() that I was then able to
use in fold_comparison().

I've made a few other small adjustments to the patch to avoid
one false positive, and a few test cases, and tweak the expected
diagnostics now that Marek has fixed 70194.

I've also wrote myself a small sed script to replace blocks of
8 spaces with tabs and ran the patch through it.  I'll integrate
it into my workflow so I hopefully don't have to worry about this
ever again.

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-17  Martin Sebor  <mse...@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-ptr9.C: New test.
	* g++.dg/cpp0x/constexpr-array5.C: Adjust text of expected diagnostic.
	* g++.dg/cpp0x/constexpr-nullptr.C: Add test cases.
	* 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-17  Martin Sebor  <mse...@redhat.com>

	PR c++/67376
	PR c++/70170
	PR c++/70172
	PR c++/60760
	PR c++/70228
	* constexpr.c (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.
	(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-17  Martin Sebor  <mse...@redhat.com>

	PR c++/67376
	* fold-const.c (maybe_nonzero_address): New function.
	(fold_comparison): Call it.  Fold equality and relational
	expressions involving null pointers.
	(tree_single_nonzero_warnv_p): Call maybe_nonzero_address.

Index: gcc/cp/constexpr.c
===================================================================
--- gcc/cp/constexpr.c	(revision 234306)
+++ gcc/cp/constexpr.c	(working copy)
@@ -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 constexp
 	  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 constex
 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 conste
 		   || 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 c
     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 dind
   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 constexp
 					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 constexp
   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 constexp
 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 cons
   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, t
 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_c
       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
 	}
       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
 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 cons
     {
       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 cons
 	  {
 	    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 cons
 	 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 cons
     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 cons
       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 cons
       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 cons
     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 cons
 	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 cons
 	    || 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 cons
     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 cons
 	  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 cons
     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,32 @@ cxx_eval_constant_expression (const cons
 		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;
+
+		tree t1 = TREE_TYPE (type);
+		tree t2 = TREE_TYPE (op);
+		if (TREE_TYPE (t2))
+		  t2 = TREE_TYPE (t2);
+		if (!same_type_ignoring_top_level_qualifiers_p (t1, t2))
+		  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 +3870,7 @@ cxx_eval_constant_expression (const cons
       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 +3919,7 @@ cxx_eval_constant_expression (const cons
 	  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 +4026,9 @@ cxx_eval_outermost_constant_expr (tree t
 	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);
 
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 234306)
+++ gcc/fold-const.c	(working copy)
@@ -8339,6 +8339,20 @@ pointer_may_wrap_p (tree base, tree offs
   return total.to_uhwi () > (unsigned HOST_WIDE_INT) size;
 }
 
+/* Return a positive integer when the symbol DECL is known to have
+   a nonzero address, zero when it's known not to (e.g., it's a weak
+   symbol), and a negative integer when the symbol is not yet in the
+   symbol table and so whether or not its address is zero is unknown.  */
+static int
+maybe_nonzero_address (tree decl)
+{
+  if (DECL_P (decl) && decl_in_symtab_p (decl))
+    if (struct symtab_node *symbol = symtab_node::get_create (decl))
+      return symbol->nonzero_address ();
+
+  return -1;
+}
+
 /* Subroutine of fold_binary.  This routine performs all of the
    transformations that are common to the equality/inequality
    operators (EQ_EXPR and NE_EXPR) and the ordering operators
@@ -8639,6 +8653,38 @@ fold_comparison (location_t loc, enum tr
 	    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)
+	       && maybe_nonzero_address (base0) > 0
+	       // && (!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
@@ -13509,16 +13555,9 @@ tree_single_nonzero_warnv_p (tree t, boo
 	/* For objects in symbol table check if we know they are non-zero.
 	   Don't do anything for variables and functions before symtab is built;
 	   it is quite possible that they will be declared weak later.  */
-	if (DECL_P (base) && decl_in_symtab_p (base))
-	  {
-	    struct symtab_node *symbol;
-
-	    symbol = symtab_node::get_create (base);
-	    if (symbol)
-	      return symbol->nonzero_address ();
-	    else
-	      return false;
-	  }
+	int nonzero_addr = maybe_nonzero_address (base);
+	if (nonzero_addr >= 0)
+	  return nonzero_addr;
 
 	/* Function local objects are never NULL.  */
 	if (DECL_P (base)
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C	(working copy)
@@ -0,0 +1,154 @@
+// 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 -Wextra" }
+
+namespace A {
+
+extern int i;
+
+constexpr int *p0 = &i;
+
+constexpr bool b0  = p0;        // { dg-warning "address of .A::i." }
+constexpr bool b1  = p0 == 0;   // { dg-warning "address of .A::i." }
+constexpr bool b2  = p0 != 0;   // { dg-warning "address of .A::i." }
+constexpr bool b3  = p0 <  0;   // { dg-warning "ordered comparison" }
+constexpr bool b4  = p0 <= 0;   // { dg-warning "ordered comparison" }
+constexpr bool b5  = p0 >  0;   // { dg-warning "ordered comparison" }
+constexpr bool b6  = p0 >= 0;   // { dg-warning "ordered comparison" }
+
+constexpr bool b7  = !p0;       // { dg-warning "address of .A::i." }
+constexpr bool b8  = 0 == p0;   // { dg-warning "address of .A::i." }
+constexpr bool b9  = 0 != p0;   // { dg-warning "address of .A::i." }
+constexpr bool b10 = 0 <  p0;   // { dg-warning "ordered comparison" }
+constexpr bool b11 = 0 <= p0;   // { dg-warning "ordered comparison" }
+constexpr bool b12 = 0 >  p0;   // { dg-warning "ordered comparison" }
+constexpr bool b13 = 0 >= p0;   // { dg-warning "ordered comparison" }
+
+}
+
+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." }
+constexpr bool b1  = p0 == 0;   // { dg-warning "address of .B::s." }
+constexpr bool b2  = p0 != 0;   // { dg-warning "address of .B::s." }
+constexpr bool b3  = p0 <  0;   // { dg-warning "ordered comparison" }
+constexpr bool b4  = p0 <= 0;   // { dg-warning "ordered comparison" }
+constexpr bool b5  = p0 >  0;   // { dg-warning "ordered comparison" }
+constexpr bool b6  = p0 >= 0;   // { dg-warning "ordered comparison" }
+
+constexpr bool b7  = !p0;       // { dg-warning "address of .B::s." }
+constexpr bool b8  = 0 == p0;   // { dg-warning "address of .B::s." }
+constexpr bool b9  = 0 != p0;   // { dg-warning "address of .B::s." }
+constexpr bool b10 = 0 <  p0;   // { dg-warning "ordered comparison" }
+constexpr bool b11 = 0 <= p0;   // { dg-warning "ordered comparison" }
+constexpr bool b12 = 0 >  p0;   // { dg-warning "ordered comparison" }
+constexpr bool b13 = 0 >= p0;   // { dg-warning "ordered comparison" }
+
+}
+
+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;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
+// Suppress warning: ordered comparison of pointer with integer zero
+
+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;
+
+#pragma GCC diagnostic pop
+
+}
+
+namespace WeakRefTest2 {
+
+extern __attribute__ ((weak)) int i;
+
+constexpr int *p1 = &i + 1;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
+// Suppress warning: ordered comparison of pointer with integer zero
+
+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;
+
+#pragma GCC diagnostic pop
+
+}
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C	(revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C	(working copy)
@@ -0,0 +1,57 @@
+// PR c++/67376 - [5/6 regression] Comparison with pointer to past-the-end
+//     of array fails inside constant expression
+// { 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));
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr.C	(working copy)
@@ -1,6 +1,152 @@
+// 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" }
+
+namespace N {
 
 constexpr int zero() { return 0; }
 
 void* ptr1 = zero();		// { dg-error "int" }
 constexpr void* ptr2 = zero();	// { dg-error "int" }
+
+}
+
+#define Assert(e)   static_assert (e, #e)
+
+
+// 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* p15 = &null ()[0];
+constexpr int* p16 = &0[null ()];
+
+Assert (p15 == null ());
+Assert (&*p15 == &*null ());
+Assert (&p15 [0] == &null () [0]);
+Assert (&null () [0] == &0 [null ()]);
+Assert (&0 [null ()]  == &null () [0]);
+Assert (&null () [0] == p0);
+Assert (p0 == &null () [0]);
+Assert (&null () [0] == p0);
+
+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.
+Assert (0 == (p0 - (int*)0));
+Assert (0 == (p0 - static_cast<int*>(0)));
+Assert (0 == (p0 - (int*)nullptr));
+Assert (0 == (p0 - static_cast<int*>(nullptr)));
+Assert (0 == (p0 - p0));
+Assert (0 == (p0 - q0));
+Assert (0 == (p0 - r0));
+Assert (0 == ((int*)0 - p0));
+Assert (0 == (static_cast<int*>(0) - p0));
+Assert (0 == ((int*)nullptr - p0));
+Assert (0 == ( static_cast<int*>(nullptr) - p0));
+Assert (0 == ( q0 - p0));
+Assert (0 == ( 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.
+Assert ( (ps == ps));
+Assert (!(ps != ps));
+Assert (!(ps <  ps));
+Assert ( (ps <= ps));
+Assert (!(ps >  ps));
+Assert ( (ps >= ps));
+
+Assert ( (ps == (S*)0));
+Assert (!(ps != (S*)0));
+Assert (!(ps <  (S*)0));
+Assert ( (ps <= (S*)0));
+Assert (!(ps >  (S*)0));
+Assert ( (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" }
+
+}
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-string.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-string.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-tuple.C	(working copy)
@@ -66,30 +66,30 @@ class background_hello
 public:
     background_hello()
     {
-      __builtin_printf("default ctor called, this=%p\n", this);
+      __builtin_printf("%s, this=%p, c=%i\n", __PRETTY_FUNCTION__, this, c);
       ++c;
     }
 
     background_hello(const background_hello &)
     {
-      __builtin_printf("copy ctor called\n");
+      __builtin_printf("%s, this=%p, c=%i\n", __PRETTY_FUNCTION__, this, c);
       ++c;
     }
 
     background_hello(background_hello &&)
     {
-      __builtin_printf("move ctor called\n");
+      __builtin_printf("%s, this=%p, c=%i\n", __PRETTY_FUNCTION__, this, c);
       ++c;
     }
 
     void operator ()() const
     {
-      __builtin_printf("void background_hello::operator()() called, this=%p\n", this);
+      __builtin_printf("%s, this=%p, c=%i\n", __PRETTY_FUNCTION__, this, c);
     }
 
     ~background_hello()
     {
-      __builtin_printf("destructor called, this=%p\n", this);
+      __builtin_printf("%s, this=%p, c=%i\n", __PRETTY_FUNCTION__, this, c);
       --c;
     }
 
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/cpp0x/pr65398.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/pr65398.C	(revision 234306)
+++ gcc/testsuite/g++.dg/cpp0x/pr65398.C	(working copy)
@@ -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');
Index: gcc/testsuite/g++.dg/ext/constexpr-vla1.C
===================================================================
--- gcc/testsuite/g++.dg/ext/constexpr-vla1.C	(revision 234306)
+++ gcc/testsuite/g++.dg/ext/constexpr-vla1.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/ext/constexpr-vla2.C
===================================================================
--- gcc/testsuite/g++.dg/ext/constexpr-vla2.C	(revision 234306)
+++ gcc/testsuite/g++.dg/ext/constexpr-vla2.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/ext/constexpr-vla3.C
===================================================================
--- gcc/testsuite/g++.dg/ext/constexpr-vla3.C	(revision 234306)
+++ gcc/testsuite/g++.dg/ext/constexpr-vla3.C	(working copy)
@@ -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" }
Index: gcc/testsuite/g++.dg/ubsan/pr63956.C
===================================================================
--- gcc/testsuite/g++.dg/ubsan/pr63956.C	(revision 234306)
+++ gcc/testsuite/g++.dg/ubsan/pr63956.C	(working copy)
@@ -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)

Reply via email to