diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 6185f98e6bd..cf19db268ad 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1291,6 +1291,12 @@ get_range_strlen_tree (tree arg, bitmap *visited,
   /* The length computed by this invocation of the function.  */
   tree val = NULL_TREE;
 
+  /* True if VAL is an optimistic (tight) bound determined from
+     the size of the character array in which the string may be
+     stored.  In that case, the computed VAL is used to set
+     PDATA->MAXBOUND.  */
+  bool tight_bound = false;
+
   /* We can end up with &(*iftmp_1)[0] here as well, so handle it.  */
   if (TREE_CODE (arg) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
@@ -1384,6 +1390,7 @@ get_range_strlen_tree (tree arg, bitmap *visited,
 	      && optype == TREE_TYPE (TREE_OPERAND (arg, 0))
 	      && array_at_struct_end_p (TREE_OPERAND (arg, 0)))
 	    *flexp = true;
+	  tight_bound = true;
 	}
       else if (TREE_CODE (arg) == COMPONENT_REF
 	       && (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1)))
@@ -1419,17 +1426,24 @@ get_range_strlen_tree (tree arg, bitmap *visited,
 	  /* Set the minimum size to zero since the string in
 	     the array could have zero length.  */
 	  pdata->minlen = ssize_int (0);
-	}
 
-      if (VAR_P (arg))
-	{
-	  tree type = TREE_TYPE (arg);
-	  if (POINTER_TYPE_P (type))
-	    type = TREE_TYPE (type);
-
-	  if (TREE_CODE (type) == ARRAY_TYPE)
+	  /* The array size determined above is an optimistic bound
+	     on the length.  If the array isn't nul-terminated the
+	     length computed by the library function would be greater.
+	     Even though using strlen to cross the subobject boundary
+	     is undefined, avoid drawing conclusions from the member
+	     type about the length here.  */
+	  tight_bound = true;
+	}
+      else if (VAR_P (arg))
+	{
+	  /* Avoid handling pointers to arrays.  GCC might misuse
+	     a pointer to an array of one bound to point to an array
+	     object of a greater bound.  */
+	  tree argtype = TREE_TYPE (arg);
+	  if (TREE_CODE (argtype) == ARRAY_TYPE)
 	    {
-	      val = TYPE_SIZE_UNIT (type);
+	      val = TYPE_SIZE_UNIT (argtype);
 	      if (!val
 		  || TREE_CODE (val) != INTEGER_CST
 		  || integer_zerop (val))
@@ -1476,6 +1490,43 @@ get_range_strlen_tree (tree arg, bitmap *visited,
   else
     pdata->maxbound = val;
 
+  if (tight_bound)
+    {
+      /* VAL computed above represents an optimistically tight bound
+	 on the length of the string based on the referenced object's
+	 or subobject's type.  Determine the conservative upper bound
+	 based on the enclosing object's size if possible.  */
+      if (rkind == SRK_LENRANGE || rkind == SRK_LENRANGE_2)
+	{
+	  poly_int64 offset;
+	  tree base = get_addr_base_and_unit_offset (arg, &offset);
+	  if (!base)
+	    {
+	      /* When the call above fails due to a non-constant offset
+		 assume the offset is zero and use the size of the whole
+		 enclosing object instead.  */
+	      base = get_base_address (arg);
+	      offset = 0;
+	    }
+	  /* If the base object is a pointer no upper bound on the length
+	     can be determined.  Otherwise the maximum length is equal to
+	     the size of the enclosing object minus the offset of
+	     the referenced subobject minus 1 (for the terminating nul).  */
+	  tree type = TREE_TYPE (base);
+	  if (TREE_CODE (type) == POINTER_TYPE
+	      || !VAR_P (base) || !(val = DECL_SIZE_UNIT (base)))
+	    val = build_all_ones_cst (size_type_node);
+	  else
+	    {
+	      val = DECL_SIZE_UNIT (base);
+	      val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
+				 size_int (offset + 1));
+	    }
+	}
+      else
+	return false;
+    }
+
   if (pdata->maxlen)
     {
       /* Adjust the more conservative bound if possible/necessary
diff --git a/gcc/testsuite/gcc.dg/strlenopt-40.c b/gcc/testsuite/gcc.dg/strlenopt-40.c
index e24b510deeb..7a97ebb8fe5 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-40.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-40.c
@@ -105,20 +105,23 @@ void elim_global_arrays (int i)
   /* Verify that the expression involving the strlen call as well
      as whatever depends on it is eliminated  from the test output.
      All these expressions must be trivially true.  */
-  ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3[0]);
-  ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3[1]);
-  ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3[6]);
-  ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3[i]);
-
-  ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7[0]);
-  ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7[1]);
-  ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7[4]);
-  ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7[0]);
-
-  ELIM_TRUE (strlen (ax_3[0]) < sizeof ax_3[0]);
-  ELIM_TRUE (strlen (ax_3[1]) < sizeof ax_3[1]);
-  ELIM_TRUE (strlen (ax_3[9]) < sizeof ax_3[9]);
-  ELIM_TRUE (strlen (ax_3[i]) < sizeof ax_3[i]);
+  ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3);
+  ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3 - sizeof *a7_3);
+  ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3 - 5 * sizeof *a7_3);
+  ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3);
+
+  ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7);
+  ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7 - sizeof *a5_7);
+  ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7 - 3 * sizeof *a5_7);
+  ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7);
+
+  /* Even when treating a multi-dimensional array as a single string
+     the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC
+     doesn't do that computation yet so avoid testing it.  */
+  ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX);
 
   ELIM_TRUE (strlen (a3) < sizeof a3);
   ELIM_TRUE (strlen (a7) < sizeof a7);
@@ -130,21 +133,25 @@ void elim_global_arrays (int i)
 
 void elim_pointer_to_arrays (void)
 {
-  ELIM_TRUE (strlen (*pa7) < 7);
-  ELIM_TRUE (strlen (*pa5) < 5);
-  ELIM_TRUE (strlen (*pa3) < 3);
-
-  ELIM_TRUE (strlen ((*pa7_3)[0]) < 3);
-  ELIM_TRUE (strlen ((*pa7_3)[1]) < 3);
-  ELIM_TRUE (strlen ((*pa7_3)[6]) < 3);
-
-  ELIM_TRUE (strlen ((*pax_3)[0]) < 3);
-  ELIM_TRUE (strlen ((*pax_3)[1]) < 3);
-  ELIM_TRUE (strlen ((*pax_3)[9]) < 3);
-
-  ELIM_TRUE (strlen ((*pa5_7)[0]) < 7);
-  ELIM_TRUE (strlen ((*pa5_7)[1]) < 7);
-  ELIM_TRUE (strlen ((*pa5_7)[4]) < 7);
+  /* Unfortunately, GCC cannot be trusted not to misuse a pointer
+     to a smaller array to point to an object of a bigger type so
+     the strlen range optimization must assume each array pointer
+     points effectively to an array of an unknown bound.  */
+  ELIM_TRUE (strlen (*pa7) < DIFF_MAX);
+  ELIM_TRUE (strlen (*pa5) < DIFF_MAX);
+  ELIM_TRUE (strlen (*pa3) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX);
 }
 
 void elim_global_arrays_and_strings (int i)
@@ -176,65 +183,33 @@ void elim_global_arrays_and_strings (int i)
 
 void elim_member_arrays_obj (int i)
 {
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 7);
-}
-
-void elim_member_arrays_ptr (struct MemArrays0 *ma0,
-			     struct MemArraysX *max,
-			     struct MemArrays7 *ma7,
-			     int i)
-{
-  ELIM_TRUE (strlen (ma0->a7_3[0]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[1]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
-
-  ELIM_TRUE (strlen (ma0->a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[0].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[1].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[1].a5_7[4]) < 7);
-  ELIM_TRUE (strlen (ma0[9].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[9].a5_7[4]) < 7);
-
-  ELIM_TRUE (strlen (ma0->a3) < sizeof ma0->a3);
-  ELIM_TRUE (strlen (ma0->a5) < sizeof ma0->a5);
-  ELIM_TRUE (strlen (ma0->a0) < DIFF_MAX - 1);
-
-  ELIM_TRUE (strlen (max->a3) < sizeof max->a3);
-  ELIM_TRUE (strlen (max->a5) < sizeof max->a5);
-  ELIM_TRUE (strlen (max->ax) < DIFF_MAX - 1);
-
-  ELIM_TRUE (strlen (ma7->a3) < sizeof max->a3);
-  ELIM_TRUE (strlen (ma7->a5) < sizeof max->a5);
-  ELIM_TRUE (strlen (ma7->a7) < DIFF_MAX - 1);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < sizeof ma0_3_5_7);
 }
 
 
@@ -255,11 +230,27 @@ void keep_global_arrays (int i)
   KEEP (strlen (a5_7[4]) < 6);
   KEEP (strlen (a5_7[i]) < 6);
 
+  /* Verify also that tests (and strlen calls) are not eliminated
+     for results greater than what would the size of the innermost
+     array suggest might be possible (in case the element array is
+     not nul-terminated), even though such calls are undefined.  */
+  KEEP (strlen (a5_7[0]) > sizeof a5_7 - 2);
+  KEEP (strlen (a5_7[1]) > sizeof a5_7 - sizeof a5_7[1] - 2);
+  KEEP (strlen (a5_7[i]) > sizeof a5_7 - 2);
+
   KEEP (strlen (ax_3[0]) < 2);
   KEEP (strlen (ax_3[1]) < 2);
   KEEP (strlen (ax_3[2]) < 2);
   KEEP (strlen (ax_3[i]) < 2);
 
+  /* Here again, verify that the ax_3 matrix is treated essentially
+     as a flat array of unknown bound for the benefit of all the
+     undefined code out there that might rely on it.  */
+  KEEP (strlen (ax_3[0]) > 3);
+  KEEP (strlen (ax_3[1]) > 9);
+  KEEP (strlen (ax_3[2]) > 99);
+  KEEP (strlen (ax_3[i]) > 999);
+
   KEEP (strlen (a3) < 2);
   KEEP (strlen (a7) < 6);
 
@@ -274,24 +265,48 @@ void keep_global_arrays (int i)
   KEEP (strlen (ax) < 1);
 }
 
-void keep_pointer_to_arrays (void)
+void keep_pointer_to_arrays (int i)
 {
   KEEP (strlen (*pa7) < 6);
   KEEP (strlen (*pa5) < 4);
   KEEP (strlen (*pa3) < 2);
 
+  /* Since GCC cannot be trusted not to misuse a pointer to a smaller
+     array to point to an object of a larger type verify that the bound
+     in a pointer to an array of a known bound isn't relied on for
+     the strlen range optimization.  If GCC is fixed to avoid these
+     misuses these tests can be removed.  */
+  KEEP (strlen (*pa7) > sizeof *pa7);
+  KEEP (strlen (*pa5) > sizeof *pa5);
+  KEEP (strlen (*pa3) > sizeof *pa3);
+
   KEEP (strlen ((*pa7_3)[0]) < 2);
   KEEP (strlen ((*pa7_3)[1]) < 2);
   KEEP (strlen ((*pa7_3)[6]) < 2);
+  KEEP (strlen ((*pa7_3)[i]) < 2);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pa7_3)[0]) > sizeof *pa7_3);
+  KEEP (strlen ((*pa7_3)[i]) > sizeof *pa7_3);
 
   KEEP (strlen ((*pax_3)[0]) < 2);
   KEEP (strlen ((*pax_3)[1]) < 2);
   KEEP (strlen ((*pax_3)[9]) < 2);
+  KEEP (strlen ((*pax_3)[i]) < 2);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pax_3)[0]) > 3);
+  KEEP (strlen ((*pax_3)[i]) > 333);
 
   KEEP (strlen ((*pa5_7)[0]) < 6);
   KEEP (strlen ((*pa5_7)[1]) < 6);
   KEEP (strlen ((*pa5_7)[4]) < 6);
-}
+  KEEP (strlen ((*pa5_7)[i]) < 6);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pa5_7)[0]) > sizeof *pa5_7);
+  KEEP (strlen ((*pa5_7)[i]) > sizeof *pa5_7);
+ }
 
 void keep_global_arrays_and_strings (int i)
 {
@@ -306,6 +321,12 @@ void keep_global_arrays_and_strings (int i)
   KEEP (strlen (i < 0 ? a7 : "123") < 5);
   KEEP (strlen (i < 0 ? a7 : "123456") < 6);
   KEEP (strlen (i < 0 ? a7 : "1234567") < 6);
+
+  /* Verify that a matrix is treated as a flat array even in a conditional
+     expression (i.e., don't assume that a7_3[0] is nul-terminated, even
+     though calling strlen() on such an array is undefined).  */
+  KEEP (strlen (i < 0 ? a7_3[0] : "") > 7);
+  KEEP (strlen (i < 0 ? a7_3[i] : "") > 7);
 }
 
 void keep_member_arrays_obj (int i)
@@ -337,6 +358,12 @@ void keep_member_arrays_obj (int i)
 
   KEEP (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 6);
   KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 6);
+
+  /* Again, verify that the .a3 array isn't assumed to necessarily
+     be nul-terminated.  */
+  KEEP (strlen (ma0_3_5_7[0][0][0].a3) > 2);
+  KEEP (strlen (ma0_3_5_7[0][0][6].a3) > 2);
+  KEEP (strlen (ma0_3_5_7[0][0][i].a3) > 2);
 }
 
 void keep_member_arrays_ptr (struct MemArrays0 *ma0,
@@ -353,6 +380,11 @@ void keep_member_arrays_ptr (struct MemArrays0 *ma0,
   KEEP (strlen (ma0->a7_3[i]) < 2);
   KEEP (strlen (ma0->a7_3[i]) < 2);
 
+  /* Again, verify that the member array isn't assumed to necessarily
+     be nul-terminated.  */
+  KEEP (strlen (ma0->a7_3[0]) > sizeof ma0->a7_3);
+  KEEP (strlen (ma0->a7_3[i]) > sizeof ma0->a7_3);
+
   KEEP (strlen (ma0->a5_7[0]) < 5);
   KEEP (strlen (ma0[0].a5_7[0]) < 5);
   KEEP (strlen (ma0[1].a5_7[0]) < 5);
@@ -361,6 +393,9 @@ void keep_member_arrays_ptr (struct MemArrays0 *ma0,
   KEEP (strlen (ma0[i].a5_7[4]) < 5);
   KEEP (strlen (ma0[i].a5_7[i]) < 5);
 
+  /* Same as above.  */
+  KEEP (strlen (ma0[i].a5_7[i]) > sizeof ma0[i].a5_7);
+
   KEEP (strlen (ma0->a0) < DIFF_MAX - 2);
   KEEP (strlen (ma0->a0) < 999);
   KEEP (strlen (ma0->a0) < 1);
@@ -389,5 +424,5 @@ void keep_pointers (const char *s)
 /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
    { dg-final { scan-tree-dump-times "call_in_false_branch_not_eliminated_" 0 "optimized" } }
 
-   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } }
-   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } } */
+   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } }
+   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-51.c b/gcc/testsuite/gcc.dg/strlenopt-51.c
index cbed11bbf58..3d879f1329a 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-51.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-51.c
@@ -1,16 +1,17 @@
 /* PR tree-optimization/77357 - strlen of constant strings not folded
    { dg-do compile }
-   { dg-options "-O2 -Wall -fdump-tree-gimple -fdump-tree-optimized" } */
+   { dg-options "-O0 -Wall -fdump-tree-gimple" } */
 
 #include "strlenopt.h"
 
 #define CONCAT(x, y) x ## y
 #define CAT(x, y) CONCAT (x, y)
-#define FAILNAME(name) CAT (call_ ## name ##_on_line_, __LINE__)
+#define FAILNAME(name, counter) \
+  CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
 
-#define FAIL(name) do {				\
-    extern void FAILNAME (name) (void);		\
-    FAILNAME (name)();				\
+#define FAIL(name, counter) do {			\
+    extern void FAILNAME (name, counter) (void);	\
+    FAILNAME (name, counter)();				\
   } while (0)
 
 /* Macro to emit a call to funcation named
@@ -19,19 +20,7 @@
    scan-tree-dump-time directive at the bottom of the test verifies
    that no such call appears in output.  */
 #define ELIM(expr) \
-  if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
-
-/* Macro to emit a call to a function named
-     call_made_in_{true,false}_branch_on_line_NNN()
-   for each call that's expected to be retained.  The dg-final
-   scan-tree-dump-time directive at the bottom of the test verifies
-   that the expected number of both kinds of calls appears in output
-   (a pair for each line with the invocation of the KEEP() macro.  */
-#define KEEP(expr)				\
-  if (expr)					\
-    FAIL (made_in_true_branch);			\
-  else						\
-    FAIL (made_in_false_branch)
+  if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
 
 #define T(s, n) ELIM (strlen (s) == n)
 
@@ -53,7 +42,7 @@ struct S
 
 const char a9[][9] = { S0, S1, S2, S3, S4, S5, S6, S7, S8 };
 
-void test_elim_a9 (int i)
+void test_elim_a9 (unsigned i)
 {
   ELIM (strlen (&a9[0][i]) > 0);
   ELIM (strlen (&a9[1][i]) > 1);
@@ -75,10 +64,10 @@ const char a9_9[][9][9] = {
   { S5, S6, S7, S8, S0, S1, S2, S3, S4 },
   { S6, S7, S8, S0, S1, S2, S3, S4, S5 },
   { S7, S8, S0, S1, S2, S3, S4, S5, S6 },
-  { S8, S0, S2, S2, S3, S4, S5, S6, S7 }
+  { S8, S0, S1, S2, S3, S4, S5, S6, S7 }
 };
 
-void test_elim_a9_9 (int i)
+void test_elim_a9_9 (unsigned i)
 {
 #undef T
 #define T(I)					\
@@ -95,27 +84,4 @@ void test_elim_a9_9 (int i)
   T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
 }
 
-#line 1000
-
-void test_keep_a9_9 (int i)
-{
-#undef T
-#define T(I)					\
-  KEEP (strlen (&a9_9[i][I][0]) > (1 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][1]) > (1 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][2]) > (2 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][3]) > (3 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][4]) > (4 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][5]) > (5 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][6]) > (6 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][7]) > (7 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][8]) > (8 + I) % 9)
-
-  T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
-}
-
-/* { dg-final { scan-tree-dump-times "strlen" 72 "gimple" } }
-   { dg-final { scan-tree-dump-times "strlen" 63 "optimized" } }
-
-   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 72 "optimized" } }
-   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 81 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
index 01ecd178211..466dcde998a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
@@ -40,7 +40,18 @@ void test_arrays (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 3);
+    /* Since it's undefined to pass an unterminated array to a %s
+       directive it would be valid to assume that S above is not
+       longer than sizeof (A->A3) but the optimization isn't done
+       because the GIMPLE representation of the %s argument isn't
+       suffficiently reliable not to confuse it for some other
+       array.  The argument length is therefore assumed to be in
+       the range [0, PTRDIFF_MAX - 2] and the sprintf result to be
+       as big as INT_MAX and possibly even negative if the function
+       were to fail due to a single directive resulting in more than
+       the 4,095 byte maximum required to be supported.
+       ASSERT (0 <= n && n < 3);
+    */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -52,7 +63,7 @@ void test_arrays (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -69,7 +80,7 @@ void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 3);
+    /* ASSERT (0 <= n && n < 3); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -81,7 +92,7 @@ void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -95,7 +106,7 @@ void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
