On 09/09/18 01:47, Jeff Law wrote:
> On 9/8/18 3:47 PM, Bernd Edlinger wrote:
>> Hi,
>>
>>
>>> -fold_builtin_strlen (location_t loc, tree type, tree arg)
>>> +fold_builtin_strlen (location_t loc, tree fndecl, tree type, tree arg)
>>>   {
>>>     if (!validate_arg (arg, POINTER_TYPE))
>>>       return NULL_TREE;
>>>     else
>>>       {
>>> -      tree len = c_strlen (arg, 0);
>>> -
>>> +      tree nonstr = NULL_TREE;
>>> +      tree len = c_strlen (arg, 0, &nonstr);
>>>         if (len)
>>> -       return fold_convert_loc (loc, type, len);
>>> +       {
>>> +         if (loc == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (arg))
>>> +           loc = EXPR_LOCATION (arg);
>>> +
>>> +         /* To avoid warning multiple times about unterminated
>>> +            arrays only warn if its length has been determined
>>> +            and is being folded to a constant.  */
>>> +         if (nonstr)
>>> +           warn_string_no_nul (loc, NULL_TREE, fndecl, nonstr);
>>> +
>>> +         return fold_convert_loc (loc, type, len);
>>> +       }
>>>
>>>         return NULL_TREE;
>>
>> If I see that right, this will do a wrong folding,
>> just to suppress duplicate warnings.
>>
>> But it will re-introduce a path to PR87053, since c_strlen
>> is supposed to return the wrong value because nonstr
>> suggests the caller is able to handle this.
>>
>> I think c_strlen should never return anything that is invalid.
>> Returning len and nonstr should be mutually exclusive events.
> Conceptually I agree and have already been looking at this.  But in
> practice I'm still on the fence.
> 
> I'm fairly unhappy with the APIs we're using here and the inconsistency
> in what nonstr means in terms of the return value from various
> functions.   We see this when we start layering the warnings on top of
> the trunk (which has the 87053 fix).  In some cases we want nonstr to
> force the function to return an "I don't know value, typically
> NULL_TREE", but in other cases we really want the function to still
> return the length and let the caller decide what to do about the
> termination problem.
> 
> It doesn't help that we also have memsize as well.
> 
> Rationalizing the APIs here is likely going to be a prereq to move forward.
> 

Yes, I agree.  The API is trying to solve everything at once, that is not good.

I have given Martin's part 2/6 patch a little massage tonight,
and reached this nice result:

XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 91)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 95)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 98)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 100)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 107)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 109)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 110)
XPASS: gcc.dg/warn-strlen-no-nul.c pr????? (test for warnings, line 118)
XPASS: gcc.dg/warn-strlen-no-nul.c bug (test for warnings, line 122)
XPASS: gcc.dg/warn-strlen-no-nul.c bug (test for warnings, line 123)

I left the test case as-is, just removed the ugly
"Prune out warnings with no location (pr?????)."
at the end of the test.

How do you like that?


Bernd.
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 264167)
+++ gcc/builtins.c	(working copy)
@@ -513,7 +513,7 @@ get_pointer_alignment (tree exp)
    [ PTR, PTR + MAXELTS ) where each element's size is ELTSIZE bytes.
    ELTSIZE must be a power of 2 less than 8.  Used by c_strlen.  */
 
-unsigned
+static unsigned
 string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
 {
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
@@ -542,6 +542,27 @@ string_length (const void *ptr, unsigned eltsize,
   return n;
 }
 
+/* For a call at LOC to a function FN that expects a string in the argument
+   ARG, issue a diagnostic due to it being a called with an argument
+   declared at NONSTR that is a character array with no terminating NUL.  */
+
+void
+warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
+{
+  if (TREE_NO_WARNING (arg))
+    return;
+
+  loc = expansion_point_location_if_in_system_header (loc);
+
+  if (warning_at (loc, OPT_Wstringop_overflow_,
+		  "%qs argument missing terminating nul", fn))
+    {
+      inform (DECL_SOURCE_LOCATION (decl),
+	      "referenced argument declared here");
+      TREE_NO_WARNING (arg) = 1;
+    }
+}
+
 /* Compute the length of a null-terminated character string or wide
    character string handling character sizes of 1, 2, and 4 bytes.
    TREE_STRING_LENGTH is not the right way because it evaluates to
@@ -559,6 +580,11 @@ string_length (const void *ptr, unsigned eltsize,
    accesses.  Note that this implies the result is not going to be emitted
    into the instruction stream.
 
+   If a not zero-terminated string value is encountered and NONSTR is
+   non-zero, the declaration of the string value is assigned to *NONSTR.
+   *NONSTR is accumulating, thus not cleared on success, therefore it has
+   to be initialized to NULL_TREE by the caller.
+
    ELTSIZE is 1 for normal single byte character strings, and 2 or
    4 for wide characer strings.  ELTSIZE is by default 1.
 
@@ -565,7 +591,7 @@ string_length (const void *ptr, unsigned eltsize,
    The value returned is of type `ssizetype'.  */
 
 tree
-c_strlen (tree src, int only_value, unsigned eltsize)
+c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
 {
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
   STRIP_NOPS (src);
@@ -574,8 +600,8 @@ tree
     {
       tree len1, len2;
 
-      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, eltsize);
-      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, eltsize);
+      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
+      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, nonstr, eltsize);
       if (tree_int_cst_equal (len1, len2))
 	return len1;
     }
@@ -582,7 +608,7 @@ tree
 
   if (TREE_CODE (src) == COMPOUND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
-    return c_strlen (TREE_OPERAND (src, 1), only_value, eltsize);
+    return c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
 
   location_t loc = EXPR_LOC_OR_LOC (src, input_location);
 
@@ -589,7 +615,8 @@ tree
   /* Offset from the beginning of the string in bytes.  */
   tree byteoff;
   tree memsize;
-  src = string_constant (src, &byteoff, &memsize, NULL);
+  tree decl;
+  src = string_constant (src, &byteoff, &memsize, &decl);
   if (src == 0)
     return NULL_TREE;
 
@@ -632,8 +659,14 @@ tree
       unsigned len = string_length (ptr, eltsize, strelts);
 
       /* Return when an embedded null character is found or none at all.  */
-      if (len < strelts || len > maxelts)
+      if (len < strelts)
 	return NULL_TREE;
+      else if (len > maxelts)
+	{
+	  if (nonstr && decl)
+	    *nonstr = decl;
+	  return NULL_TREE;
+	}
 
       /* We don't know the starting offset, but we do know that the string
 	 has no internal zero bytes.  If the offset falls within the bounds
@@ -694,7 +727,11 @@ tree
   /* Don't know what to return if there was no zero termination. 
      Ideally this would turn into a gcc_checking_assert over time.  */
   if (len > maxelts - eltoff)
-    return NULL_TREE;
+    {
+      if (nonstr && decl)
+	*nonstr = decl;
+      return NULL_TREE;
+    }
 
   return ssize_int (len);
 }
@@ -8373,11 +8410,24 @@ fold_builtin_strlen (location_t loc, tree type, tr
     return NULL_TREE;
   else
     {
-      tree len = c_strlen (arg, 0);
+      tree nonstr = NULL_TREE;
+      tree len = c_strlen (arg, 0, &nonstr);
 
       if (len)
 	return fold_convert_loc (loc, type, len);
 
+      if (!nonstr)
+	c_strlen (arg, 1, &nonstr); /* TODO: add test coverage here.  */
+
+      if (nonstr)
+	{
+	  if (EXPR_HAS_LOCATION (arg))
+	    loc = EXPR_LOCATION (arg);
+	  else if (loc == UNKNOWN_LOCATION)
+	    loc = input_location;
+	  warn_string_no_nul (loc, "strlen", arg, nonstr);
+	}
+
       return NULL_TREE;
     }
 }
Index: gcc/builtins.h
===================================================================
--- gcc/builtins.h	(revision 264167)
+++ gcc/builtins.h	(working copy)
@@ -56,8 +56,7 @@ extern unsigned int get_object_alignment (tree);
 extern bool get_pointer_alignment_1 (tree, unsigned int *,
 				     unsigned HOST_WIDE_INT *);
 extern unsigned int get_pointer_alignment (tree);
-extern unsigned string_length (const void*, unsigned, unsigned);
-extern tree c_strlen (tree, int, unsigned = 1);
+extern tree c_strlen (tree, int, tree * = NULL, unsigned = 1);
 extern void expand_builtin_setjmp_setup (rtx, rtx);
 extern void expand_builtin_setjmp_receiver (rtx);
 extern void expand_builtin_update_setjmp_buf (rtx);
@@ -103,6 +102,7 @@ extern bool target_char_cst_p (tree t, char *p);
 extern internal_fn associated_internal_fn (tree);
 extern internal_fn replacement_internal_fn (gcall *);
 
+extern void warn_string_no_nul (location_t, const char *, tree, tree);
 extern tree max_object_size ();
 
 #endif /* GCC_BUILTINS_H */
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 264167)
+++ gcc/expr.c	(working copy)
@@ -11303,15 +11303,11 @@ is_aligning_offset (const_tree offset, const_tree
 /* Return the tree node if an ARG corresponds to a string constant or zero
    if it doesn't.  If we return nonzero, set *PTR_OFFSET to the (possibly
    non-constant) offset in bytes within the string that ARG is accessing.
-   If NONSTR is non-null, consider valid even sequences of characters that
-   aren't nul-terminated strings.  In that case, if ARG refers to such
-   a sequence set *NONSTR to its declaration and clear it otherwise.
-   The type of the offset is sizetype.  If MEM_SIZE is non-zero the storage
-   size of the memory is returned.  If MEM_SIZE is zero, the string is
-   only returned when it is properly zero terminated.  */
+   If MEM_SIZE is non-zero the storage size of the memory is returned.
+   If DECL is non-zero the constant declaration is returned if available.  */
 
 tree
-string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *nonstr)
+string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 {
   tree array;
   STRIP_NOPS (arg);
@@ -11340,6 +11336,12 @@ tree
 
 	      if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
 		return NULL_TREE;
+
+	      if (!integer_zerop (array_ref_low_bound (arg)))
+		return NULL_TREE;
+
+	      if (!integer_onep (array_ref_element_size (arg)))
+		return NULL_TREE;
 	    }
 	}
       array = get_addr_base_and_unit_offset (ref, &base_off);
@@ -11365,7 +11367,7 @@ tree
 	return NULL_TREE;
 
       tree offset;
-      if (tree str = string_constant (arg0, &offset, mem_size, nonstr))
+      if (tree str = string_constant (arg0, &offset, mem_size, decl))
 	{
 	  /* Avoid pointers to arrays (see bug 86622).  */
 	  if (POINTER_TYPE_P (TREE_TYPE (arg))
@@ -11395,11 +11397,7 @@ tree
       if (TREE_CODE (chartype) != INTEGER_TYPE)
 	return NULL;
 
-      tree charsize = array_ref_element_size (arg);
-      /* Set the non-constant offset to the non-constant index scaled
-	 by the size of the character type.  */
-      offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset),
-			    fold_convert (sizetype, varidx), charsize);
+      offset = fold_convert (sizetype, varidx);
     }
 
   if (TREE_CODE (array) == STRING_CST)
@@ -11407,9 +11405,8 @@ tree
       *ptr_offset = fold_convert (sizetype, offset);
       if (mem_size)
 	*mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
-      /* This is not strictly correct.  FIXME in follow-up patch.  */
-      if (nonstr)
-	*nonstr = NULL_TREE;
+      if (decl)
+	*decl = NULL_TREE;
       return array;
     }
 
@@ -11452,41 +11449,15 @@ tree
   if (!init || TREE_CODE (init) != STRING_CST)
     return NULL_TREE;
 
-  tree array_size = DECL_SIZE_UNIT (array);
-  if (!array_size || TREE_CODE (array_size) != INTEGER_CST)
-    return NULL_TREE;
-
-  /* Avoid returning an array that is unterminated because it lacks
-     a terminating nul, like
-     const char a[4] = "abcde";
-     but do handle those that are strings even if they have excess
-     initializers, such as in
-     const char a[4] = "abc\000\000";
-     The excess elements contribute to TREE_STRING_LENGTH()
-     but not to strlen().  */
-  unsigned HOST_WIDE_INT charsize
-    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (init))));
-  /* Compute the lower bound number of elements (not bytes) in the array
-     that the string is used to initialize.  The actual size of the array
-     may be greater if the string is shorter, but the the important
-     data point is whether the literal, inlcuding the terminating nul,
-     fits the array.  */
-  unsigned HOST_WIDE_INT array_elts
-    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (init))) / charsize;
-
-  /* Compute the string length in (wide) characters.  */
-  unsigned HOST_WIDE_INT length = TREE_STRING_LENGTH (init);
-  length = string_length (TREE_STRING_POINTER (init), charsize,
-			  length / charsize);
   if (mem_size)
     *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (init));
-  if (nonstr)
-    *nonstr = array_elts > length ? NULL_TREE : array;
-
-  if ((!mem_size && !nonstr)
-      && array_elts <= length)
+  else if (compare_tree_int (TYPE_SIZE_UNIT (TREE_TYPE (init)),
+			     TREE_STRING_LENGTH (init)) < 0)
     return NULL_TREE;
 
+  if (decl)
+    *decl = array;
+
   *ptr_offset = offset;
   return init;
 }
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 264167)
+++ gcc/fold-const.c	(working copy)
@@ -14576,23 +14576,20 @@ fold_build_pointer_plus_hwi_loc (location_t loc, t
 /* Return a pointer P to a NUL-terminated string representing the sequence
    of constant characters referred to by SRC (or a subsequence of such
    characters within it if SRC is a reference to a string plus some
-   constant offset).  If STRLEN is non-null, store stgrlen(P) in *STRLEN.
-   If STRSIZE is non-null, store in *STRSIZE the size of the array
-   the string is stored in; in that case, even though P points to a NUL
-   terminated string, SRC need not refer to one.  This can happen when
-   SRC refers to a constant character array initialized to all non-NUL
-   values, as in the C declaration: char a[4] = "1234";  */
+   constant offset).  If STRLEN is non-null, store the number of bytes
+   in the string constant including the terminating NUL char.  *STRLEN is
+   typically strlen(P) + 1 in the absence of embedded NUL characters.  */
 
 const char *
-c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
-	  unsigned HOST_WIDE_INT *strsize /* = NULL */)
+c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */)
 {
   tree offset_node;
+  tree mem_size;
 
   if (strlen)
     *strlen = 0;
 
-  src = string_constant (src, &offset_node, NULL, NULL);
+  src = string_constant (src, &offset_node, &mem_size, NULL);
   if (src == 0)
     return NULL;
 
@@ -14605,25 +14602,18 @@ const char *
 	offset = tree_to_uhwi (offset_node);
     }
 
+  if (!tree_fits_uhwi_p (mem_size))
+    return NULL;
+
   /* STRING_LENGTH is the size of the string literal, including any
      embedded NULs.  STRING_SIZE is the size of the array the string
      literal is stored in.  */
   unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
-  unsigned HOST_WIDE_INT string_size = string_length;
-  tree type = TREE_TYPE (src);
-  if (tree size = TYPE_SIZE_UNIT (type))
-    if (tree_fits_shwi_p (size))
-      string_size = tree_to_uhwi (size);
+  unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size);
 
-  if (strlen)
-    {
-      /* Compute and store the length of the substring at OFFSET.
-	 All offsets past the initial length refer to null strings.  */
-      if (offset <= string_length)
-	*strlen = string_length - offset;
-      else
-	*strlen = 0;
-    }
+  /* Ideally this would turn into a gcc_checking_assert over time.  */
+  if (string_length > string_size)
+    string_length = string_size;
 
   const char *string = TREE_STRING_POINTER (src);
 
@@ -14631,21 +14621,26 @@ const char *
       || offset >= string_size)
     return NULL;
 
-  if (strsize)
+  if (strlen)
     {
-      /* Support even constant character arrays that aren't proper
-	 NUL-terminated strings.  */
-      *strsize = string_size;
+      /* Compute and store the length of the substring at OFFSET.
+	 All offsets past the initial length refer to null strings.  */
+      if (offset < string_length)
+	*strlen = string_length - offset;
+      else
+	*strlen = 1;
     }
-  else if (string[string_length - 1] != '\0')
+  else
     {
-      /* Support only properly NUL-terminated strings but handle
-	 consecutive strings within the same array, such as the six
-	 substrings in "1\0002\0003".  */
-      return NULL;
+      tree eltype = TREE_TYPE (TREE_TYPE (src));
+      /* Support only properly NUL-terminated single byte strings.  */
+      if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1)
+	return NULL;
+      if (string[string_length - 1] != '\0')
+	return NULL;
     }
 
-  return offset <= string_length ? string + offset : "";
+  return offset < string_length ? string + offset : "";
 }
 
 /* Given a tree T, compute which bits in T may be nonzero.  */
Index: gcc/fold-const.h
===================================================================
--- gcc/fold-const.h	(revision 264167)
+++ gcc/fold-const.h	(working copy)
@@ -187,8 +187,7 @@ extern bool expr_not_equal_to (tree t, const wide_
 extern tree const_unop (enum tree_code, tree, tree);
 extern tree const_binop (enum tree_code, tree, tree, tree);
 extern bool negate_mathfn_p (combined_fn);
-extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL,
-			     unsigned HOST_WIDE_INT * = NULL);
+extern const char *c_getstr (tree, unsigned HOST_WIDE_INT * = NULL);
 extern wide_int tree_nonzero_bits (const_tree);
 
 /* Return OFF converted to a pointer offset type suitable as offset for
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 264167)
+++ gcc/gimple-fold.c	(working copy)
@@ -1331,7 +1331,7 @@ get_range_strlen (tree arg, tree length[2], bitmap
 	    return false;
 	}
       else
-	val = c_strlen (arg, 1, eltsize);
+	val = c_strlen (arg, 1, NULL, eltsize);
 
       if (!val && fuzzy)
 	{
Index: gcc/gimple-ssa-sprintf.c
===================================================================
--- gcc/gimple-ssa-sprintf.c	(revision 264167)
+++ gcc/gimple-ssa-sprintf.c	(working copy)
@@ -1999,13 +1999,6 @@ get_string_length (tree str, unsigned eltsize)
   if (!str)
     return fmtresult ();
 
-  if (tree slen = c_strlen (str, 1, eltsize))
-    {
-      /* Simply return the length of the string.  */
-      fmtresult res (tree_to_shwi (slen));
-      return res;
-    }
-
   /* Determine the length of the shortest and longest string referenced
      by STR.  Strings of unknown lengths are bounded by the sizes of
      arrays that subexpressions of STR may refer to.  Pointers that
Index: gcc/testsuite/gcc.dg/warn-strlen-no-nul.c
===================================================================
--- gcc/testsuite/gcc.dg/warn-strlen-no-nul.c	(revision 0)
+++ gcc/testsuite/gcc.dg/warn-strlen-no-nul.c	(working copy)
@@ -0,0 +1,301 @@
+/* PR tree-optimization/86552 - missing warning for reading past the end
+   of non-string arrays
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+extern __SIZE_TYPE__ strlen (const char*);
+
+const char a[5] = "12345";   /* { dg-message "declared here" } */
+
+int v0 = 0;
+int v1 = 1;
+
+void sink (int, ...);
+
+#define CONCAT(a, b)   a ## b
+#define CAT(a, b)      CONCAT(a, b)
+
+#define T(str)						\
+  __attribute__ ((noipa))				\
+  void CAT (test_, __LINE__) (void) {			\
+    int i0 = 0, i1 = i0 + 1, i2 = i1 + 1, i3 = i2 + 1;	\
+    sink (strlen (str), i0, i1, i2, i3);		\
+  } typedef void dummy_type
+
+T (a);                /* { dg-warning "argument missing terminating nul" }  */
+T (&a[0]);            /* { dg-warning "nul" }  */
+T (&a[0] + 1);        /* { dg-warning "nul" }  */
+T (&a[1]);            /* { dg-warning "nul" }  */
+T (&a[v0]);           /* { dg-warning "nul" }  */
+T (&a[v0] + 1);       /* { dg-warning "nul" }  */
+
+
+const char b[][5] = { /* { dg-message "declared here" } */
+  "12", "123", "1234", "54321"
+};
+
+T (b[0]);
+T (b[1]);
+T (b[2]);
+T (b[3]);             /* { dg-warning "nul" }  */
+
+T (b[i0]);
+T (b[i1]);
+T (b[i2]);
+T (b[i3]);            /* { dg-warning "nul" }  */
+
+T (b[v0]);
+
+T (&b[i2][i1]);
+T (&b[i2][i1] + i1);
+T (&b[i2][v0]);
+T (&b[i2][i1] + v0);
+
+T (&b[2][1]);
+T (&b[2][1] + i1);
+T (&b[2][i0]);
+T (&b[2][1] + i0);
+
+T (&b[2][1]);
+T (&b[2][1] + v0);
+T (&b[2][v0]);
+
+T (&b[3][1]);           /* { dg-warning "nul" }  */
+T (&b[3][1] + 1);       /* { dg-warning "nul" }  */
+T (&b[3][1] + i1);      /* { dg-warning "nul" }  */
+T (&b[3][v0]);          /* { dg-warning "nul" }  */
+T (&b[3][1] + v0);      /* { dg-warning "nul" }  */
+T (&b[3][v0] + v1);     /* { dg-warning "nul" }  */
+
+T (&b[i3][i1]);         /* { dg-warning "nul" }  */
+T (&b[i3][i1] + 1);     /* { dg-warning "nul" }  */
+T (&b[i3][i1] + i1);    /* { dg-warning "nul" }  */
+T (&b[i3][v0]);         /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&b[i3][i1] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&b[i3][v0] + v1);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+
+T (v0 ? "" : b[0]);
+T (v0 ? "" : b[1]);
+T (v0 ? "" : b[2]);
+T (v0 ? "" : b[3]);               /* { dg-warning "nul" }  */
+T (v0 ? b[0] : "");
+T (v0 ? b[1] : "");
+T (v0 ? b[2] : "");
+T (v0 ? b[3] : "");               /* { dg-warning "nul" }  */
+
+T (v0 ? "" : b[i0]);
+T (v0 ? "" : b[i1]);
+T (v0 ? "" : b[i2]);
+/* The following is diagnosed but the warning location is wrong
+   (the PRE pass loses it).  */
+T (v0 ? "" : b[i3]);              /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+T (v0 ? b[i0] : "");
+T (v0 ? b[i1] : "");
+T (v0 ? b[i2] : "");
+T (v0 ? b[i3] : "");              /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+
+T (v0 ? "1234" : b[3]);           /* { dg-warning "nul" }  */
+T (v0 ? "1234" : b[i3]);          /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+T (v0 ? b[3] : "1234");           /* { dg-warning "nul" }  */
+T (v0 ? b[i3] : "1234");          /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+
+T (v0 ? a : b[3]);                /* { dg-warning "nul" }  */
+T (v0 ? b[0] : b[2]);
+T (v0 ? b[2] : b[3]);             /* { dg-warning "nul" }  */
+T (v0 ? b[3] : b[2]);             /* { dg-warning "nul" }  */
+
+T (v0 ? a : b[i3]);               /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+T (v0 ? b[i0] : b[i2]);
+T (v0 ? b[i2] : b[i3]);           /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+T (v0 ? b[i3] : b[i2]);           /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+
+T (v0 ? b[0] : &b[3][0] + 1);     /* { dg-warning "nul" }  */
+T (v0 ? b[0] : &b[3][0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[1] : &b[3][1] + v0);    /* { dg-warning "nul" }  */
+
+T (v0 ? b[i0] : &b[i3][i0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[i0] : &b[i3][i0] + i1);    /* { dg-warning "nul" }  */
+T (v0 ? b[i1] : &b[i3][i1] + v0);    /* { dg-warning "nul" "pr?????" { xfail *-*-* } }  */
+
+/* It's possible to detect the missing nul in the following two
+   expressions but GCC doesn't do it yet.  */
+T (v0 ? &b[3][1] + v0 : b[2]);    /* { dg-warning "nul" "bug" { xfail *-*-* } }  */
+T (v0 ? &b[3][v0] : &b[3][v1]);   /* { dg-warning "nul" "bug" { xfail *-*-* } }  */
+
+
+struct A { char a[5], b[5]; };
+
+const struct A s = { "1234", "12345" };
+
+T (s.a);
+T (&s.a[0]);
+T (&s.a[0] + 1);
+T (&s.a[0] + v0);
+T (&s.a[1]);
+T (&s.a[1] + 1);
+T (&s.a[1] + v0);
+
+T (&s.a[i0]);
+T (&s.a[i0] + i1);
+T (&s.a[i0] + v0);
+T (&s.a[i1]);
+T (&s.a[i1] + i1);
+T (&s.a[i1] + v0);
+
+T (s.b);              /* { dg-warning "nul" }  */
+T (&s.b[0]);          /* { dg-warning "nul" }  */
+T (&s.b[0] + 1);      /* { dg-warning "nul" }  */
+T (&s.b[0] + v0);     /* { dg-warning "nul" }  */
+T (&s.b[1]);          /* { dg-warning "nul" }  */
+T (&s.b[1] + 1);      /* { dg-warning "nul" }  */
+T (&s.b[1] + i0);     /* { dg-warning "nul" }  */
+T (&s.b[1] + v0);     /* { dg-warning "nul" }  */
+
+T (&s.b[i0]);         /* { dg-warning "nul" }  */
+T (&s.b[i0] + i1);    /* { dg-warning "nul" }  */
+T (&s.b[i0] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+T (&s.b[i1]);         /* { dg-warning "nul" }  */
+T (&s.b[i1] + i1);    /* { dg-warning "nul" }  */
+T (&s.b[i1] + v0);    /* { dg-warning "nul" "pr86919" { xfail *-*-* } }  */
+
+struct B { struct A a[2]; };
+
+const struct B ba[] = {
+  { { { "123", "12345" }, { "12345", "123" } } },
+  { { { "12345", "123" }, { "123", "12345" } } },
+  { { { "1", "12" },      { "123", "1234" } } },
+  { { { "123", "1234" },  { "12345", "12" } } }
+};
+
+T (ba[0].a[0].a);
+T (&ba[0].a[0].a[0]);
+T (&ba[0].a[0].a[0] + 1);
+T (&ba[0].a[0].a[0] + v0);
+T (&ba[0].a[0].a[1]);
+T (&ba[0].a[0].a[1] + 1);
+T (&ba[0].a[0].a[1] + v0);
+
+T (ba[0].a[0].b);           /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[0].b[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[0].a[1].a);           /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1]);       /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[0].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[0].a[1].b);
+T (&ba[0].a[1].b[0]);
+T (&ba[0].a[1].b[0] + 1);
+T (&ba[0].a[1].b[0] + v0);
+T (&ba[0].a[1].b[1]);
+T (&ba[0].a[1].b[1] + 1);
+T (&ba[0].a[1].b[1] + v0);
+
+
+T (ba[1].a[0].a);           /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[0].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[1].a[0].b);
+T (&ba[1].a[0].b[0]);
+T (&ba[1].a[0].b[0] + 1);
+T (&ba[1].a[0].b[0] + v0);
+T (&ba[1].a[0].b[1]);
+T (&ba[1].a[0].b[1] + 1);
+T (&ba[1].a[0].b[1] + v0);
+
+T (ba[1].a[1].a);
+T (&ba[1].a[1].a[0]);
+T (&ba[1].a[1].a[0] + 1);
+T (&ba[1].a[1].a[0] + v0);
+T (&ba[1].a[1].a[1]);
+T (&ba[1].a[1].a[1] + 1);
+T (&ba[1].a[1].a[1] + v0);
+
+T (ba[1].a[1].b);           /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1]);       /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[1].a[1].b[1] + v0);  /* { dg-warning "nul" }  */
+
+
+T (ba[2].a[0].a);
+T (&ba[2].a[0].a[0]);
+T (&ba[2].a[0].a[0] + 1);
+T (&ba[2].a[0].a[0] + v0);
+T (&ba[2].a[0].a[1]);
+T (&ba[2].a[0].a[1] + 1);
+T (&ba[2].a[0].a[1] + v0);
+
+T (ba[2].a[0].b);
+T (&ba[2].a[0].b[0]);
+T (&ba[2].a[0].b[0] + 1);
+T (&ba[2].a[0].b[0] + v0);
+T (&ba[2].a[0].b[1]);
+T (&ba[2].a[0].b[1] + 1);
+T (&ba[2].a[0].b[1] + v0);
+
+T (ba[2].a[1].a);
+T (&ba[2].a[1].a[0]);
+T (&ba[2].a[1].a[0] + 1);
+T (&ba[2].a[1].a[0] + v0);
+T (&ba[2].a[1].a[1]);
+T (&ba[2].a[1].a[1] + 1);
+T (&ba[2].a[1].a[1] + v0);
+
+
+T (ba[3].a[0].a);
+T (&ba[3].a[0].a[0]);
+T (&ba[3].a[0].a[0] + 1);
+T (&ba[3].a[0].a[0] + v0);
+T (&ba[3].a[0].a[1]);
+T (&ba[3].a[0].a[1] + 1);
+T (&ba[3].a[0].a[1] + v0);
+
+T (ba[3].a[0].b);
+T (&ba[3].a[0].b[0]);
+T (&ba[3].a[0].b[0] + 1);
+T (&ba[3].a[0].b[0] + v0);
+T (&ba[3].a[0].b[1]);
+T (&ba[3].a[0].b[1] + 1);
+T (&ba[3].a[0].b[1] + v0);
+
+T (ba[3].a[1].a);           /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0]);	    /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1]);	    /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+T (&ba[3].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+T (ba[3].a[1].b);
+T (&ba[3].a[1].b[0]);
+T (&ba[3].a[1].b[0] + 1);
+T (&ba[3].a[1].b[0] + v0);
+T (&ba[3].a[1].b[1]);
+T (&ba[3].a[1].b[1] + 1);
+T (&ba[3].a[1].b[1] + v0);
+
+
+T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" }  */
+T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" }  */
+
+T (v0 ? &ba[0].a[0].a[0] : &ba[3].a[1].a[0]);   /* { dg-warning "nul" }  */
+T (v0 ? &ba[3].a[1].a[1] :  ba[0].a[0].a);      /* { dg-warning "nul" }  */
+
+T (v0 ? ba[0].a[0].a : ba[0].a[1].b);
+T (v0 ? ba[0].a[1].b : ba[0].a[0].a);
Index: gcc/tree-ssa-strlen.c
===================================================================
--- gcc/tree-ssa-strlen.c	(revision 264167)
+++ gcc/tree-ssa-strlen.c	(working copy)
@@ -291,8 +291,6 @@ get_addr_stridx (tree exp, tree ptr, unsigned HOST
 static int
 get_stridx (tree exp)
 {
-  tree s, o;
-
   if (TREE_CODE (exp) == SSA_NAME)
     {
       if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
@@ -336,18 +334,10 @@ get_stridx (tree exp)
 	return idx;
     }
 
-  s = string_constant (exp, &o, NULL, NULL);
-  if (s != NULL_TREE
-      && (o == NULL_TREE || tree_fits_shwi_p (o))
-      && TREE_STRING_LENGTH (s) > 0)
-    {
-      HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
-      const char *p = TREE_STRING_POINTER (s);
-      int max = TREE_STRING_LENGTH (s) - 1;
+  const char *p = c_getstr (exp);
+  if (p)
+    return ~(int) strlen (p);
 
-      if (p[max] == '\0' && offset >= 0 && offset <= max)
-	return ~(int) strlen (p + offset);
-    }
   return 0;
 }
 

Reply via email to