PR middle-end/91490 - bogus argument missing terminating nul warning on strlen of...
authorMartin Sebor <msebor@redhat.com>
Thu, 22 Aug 2019 23:09:26 +0000 (23:09 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 22 Aug 2019 23:09:26 +0000 (17:09 -0600)
gcc/c-family/ChangeLog:

PR middle-end/91490
* c-common.c (braced_list_to_string): Add argument and overload.
Handle flexible length arrays and unions.

gcc/testsuite/ChangeLog:

PR middle-end/91490
* c-c++-common/Warray-bounds-7.c: New test.
* gcc.dg/Warray-bounds-39.c: Expect either -Warray-bounds or
-Wstringop-overflow.
* gcc.dg/strlenopt-78.c: New test.

gcc/ChangeLog:

PR middle-end/91490
* builtins.c (c_strlen): Rename argument and introduce new local.
Set no-warning bit on original argument.
* expr.c (string_constant): Pass argument type to fold_ctor_reference.
Fold empty and zero constructors into empty strings.
* gimple-fold.c (fold_nonarray_ctor_reference): Return a STRING_CST
for missing initializers.
* tree.c (build_string_literal): Handle optional argument.
* tree.h (build_string_literal): Add defaulted argument.
* gimple-ssa-warn-restrict.c (maybe_diag_access_bounds): Check
no-warning bit on original expression.

From-SVN: r274837

13 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/expr.c
gcc/gimple-fold.c
gcc/gimple-ssa-warn-restrict.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Warray-bounds-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Warray-bounds-39.c
gcc/testsuite/gcc.dg/strlenopt-78.c [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 3ef76cefb8606b3a1ce65adc72fc95b68006eb68..2651ce2daf07561c42514136048b36401cba41d6 100644 (file)
@@ -1,3 +1,17 @@
+2019-08-22  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/91490
+       * builtins.c (c_strlen): Rename argument and introduce new local.
+       Set no-warning bit on original argument.
+       * expr.c (string_constant): Pass argument type to fold_ctor_reference.
+       Fold empty and zero constructors into empty strings.
+       * gimple-fold.c (fold_nonarray_ctor_reference): Return a STRING_CST
+       for missing initializers.
+       * tree.c (build_string_literal): Handle optional argument.
+       * tree.h (build_string_literal): Add defaulted argument.
+       * gimple-ssa-warn-restrict.c (maybe_diag_access_bounds): Check
+       no-warning bit on original expression.
+
 2019-08-22  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR target/91481
index 9a766e4ad63cdee7520def5e522bb937e418dbe8..073b92a1dc9548b2de6142b05abd7eb3248508e4 100644 (file)
@@ -620,7 +620,7 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
    into the instruction stream and zero if it is going to be expanded.
    E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is nonzero, constant 3
    is returned, otherwise NULL, since
-   len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
+   len = c_strlen (ARG, 1); if (len) expand_expr (len, ...); would not
    evaluate the side-effects.
 
    If ONLY_VALUE is two then we do not emit warnings about out-of-bound
@@ -628,7 +628,7 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
    into the instruction stream.
 
    Additional information about the string accessed may be recorded
-   in DATA.  For example, if SRC references an unterminated string,
+   in DATA.  For example, if ARG references an unterminated string,
    then the declaration will be stored in the DECL field.   If the
    length of the unterminated string can be determined, it'll be
    stored in the LEN field.  Note this length could well be different
@@ -640,7 +640,7 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
    The value returned is of type `ssizetype'.  */
 
 tree
-c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
+c_strlen (tree arg, int only_value, c_strlen_data *data, unsigned eltsize)
 {
   /* If we were not passed a DATA pointer, then get one to a local
      structure.  That avoids having to check DATA for NULL before
@@ -650,7 +650,8 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
     data = &local_strlen_data;
 
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
-  STRIP_NOPS (src);
+
+  tree src = STRIP_NOPS (arg);
   if (TREE_CODE (src) == COND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
     {
@@ -762,11 +763,15 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
     {
       /* Suppress multiple warnings for propagated constant strings.  */
       if (only_value != 2
-         && !TREE_NO_WARNING (src)
+         && !TREE_NO_WARNING (arg)
          && warning_at (loc, OPT_Warray_bounds,
                         "offset %qwi outside bounds of constant string",
                         eltoff))
-       TREE_NO_WARNING (src) = 1;
+       {
+         if (decl)
+           inform (DECL_SOURCE_LOCATION (decl), "%qE declared here", decl);
+         TREE_NO_WARNING (arg) = 1;
+       }
       return NULL_TREE;
     }
 
index c8721406b17a09caa716f109946bcfbcba11fd99..a1a864a8e976afd89de1f35cb6fae937806121ed 100644 (file)
@@ -1,3 +1,9 @@
+2019-08-22  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/91490
+       * c-common.c (braced_list_to_string): Add argument and overload.
+       Handle flexible length arrays and unions.
+
 2019-08-21  Eric Botcazou  <ebotcazou@adacore.com>
 
        * c-ada-spec.c (dump_ada_function_declaration): Be prepared for broken
index 2810867235d952f58f9844724d993f6c59808d99..0aaa246d3ccd73afedff60c5e9c7380ba06877e7 100644 (file)
@@ -8747,9 +8747,12 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
    the converted string on success or the original ctor on failure.  */
 
 static tree
-braced_list_to_string (tree type, tree ctor)
+braced_list_to_string (tree type, tree ctor, bool member)
 {
-  if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
+  /* Ignore non-members with unknown size like arrays with unspecified
+     bound.  */
+  tree typesize = TYPE_SIZE_UNIT (type);
+  if (!member && !tree_fits_uhwi_p (typesize))
     return ctor;
 
   /* If the array has an explicit bound, use it to constrain the size
@@ -8757,10 +8760,17 @@ braced_list_to_string (tree type, tree ctor)
      as long as implied by the index of the last zero specified via
      a designator, as in:
        const char a[] = { [7] = 0 };  */
-  unsigned HOST_WIDE_INT maxelts = tree_to_uhwi (TYPE_SIZE_UNIT (type));
-  maxelts /= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+  unsigned HOST_WIDE_INT maxelts;
+  if (typesize)
+    {
+      maxelts = tree_to_uhwi (typesize);
+      maxelts /= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+    }
+  else
+    maxelts = HOST_WIDE_INT_M1U;
 
-  /* Avoid converting initializers for zero-length arrays.  */
+  /* Avoid converting initializers for zero-length arrays (but do
+     create them for flexible array members).  */
   if (!maxelts)
     return ctor;
 
@@ -8818,7 +8828,7 @@ braced_list_to_string (tree type, tree ctor)
     }
 
   /* Append a nul string termination.  */
-  if (str.length () < maxelts)
+  if (maxelts != HOST_WIDE_INT_M1U && str.length () < maxelts)
     str.safe_push (0);
 
   /* Build a STRING_CST with the same type as the array.  */
@@ -8827,14 +8837,12 @@ braced_list_to_string (tree type, tree ctor)
   return res;
 }
 
-/* Attempt to convert a CTOR containing braced array initializer lists
-   for array TYPE into one containing STRING_CSTs, for convenience and
-   efficiency.  Recurse for arrays of arrays and member initializers.
-   Return the converted CTOR or STRING_CST on success or the original
-   CTOR otherwise.  */
+/* Implementation of the two-argument braced_lists_to_string withe
+   the same arguments plus MEMBER which is set for struct members
+   to allow initializers for flexible member arrays.  */
 
-tree
-braced_lists_to_strings (tree type, tree ctor)
+static tree
+braced_lists_to_strings (tree type, tree ctor, bool member)
 {
   if (TREE_CODE (ctor) != CONSTRUCTOR)
     return ctor;
@@ -8858,17 +8866,19 @@ braced_lists_to_strings (tree type, tree ctor)
 
   if ((TREE_CODE (ttp) == ARRAY_TYPE || TREE_CODE (ttp) == INTEGER_TYPE)
       && TYPE_STRING_FLAG (ttp))
-    return braced_list_to_string (type, ctor);
+    return braced_list_to_string (type, ctor, member);
 
   code = TREE_CODE (ttp);
-  if (code == ARRAY_TYPE || code == RECORD_TYPE)
+  if (code == ARRAY_TYPE || RECORD_OR_UNION_TYPE_P (ttp))
     {
+      bool rec = RECORD_OR_UNION_TYPE_P (ttp);
+
       /* Handle array of arrays or struct member initializers.  */
       tree val;
       unsigned HOST_WIDE_INT idx;
       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
        {
-         val = braced_lists_to_strings (ttp, val);
+         val = braced_lists_to_strings (ttp, val, rec);
          CONSTRUCTOR_ELT (ctor, idx)->value = val;
        }
     }
@@ -8876,4 +8886,16 @@ braced_lists_to_strings (tree type, tree ctor)
   return ctor;
 }
 
+/* Attempt to convert a CTOR containing braced array initializer lists
+   for array TYPE into one containing STRING_CSTs, for convenience and
+   efficiency.  Recurse for arrays of arrays and member initializers.
+   Return the converted CTOR or STRING_CST on success or the original
+   CTOR otherwise.  */
+
+tree
+braced_lists_to_strings (tree type, tree ctor)
+{
+  return braced_lists_to_strings (type, ctor, false);
+}
+
 #include "gt-c-family-c-common.h"
index 92979289e83105695fecc781574014f34e3bd732..5ca0e20f14ae174b0bf112673f3e653b77c961c9 100644 (file)
@@ -11402,6 +11402,15 @@ is_aligning_offset (const_tree offset, const_tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 {
+  tree dummy = NULL_TREE;;
+  if (!mem_size)
+    mem_size = &dummy;
+
+  /* Store the type of the original expression before conversions
+     via NOP_EXPR or POINTER_PLUS_EXPR to other types have been
+     removed.  */
+  tree argtype = TREE_TYPE (arg);
+
   tree array;
   STRIP_NOPS (arg);
 
@@ -11464,7 +11473,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
              && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == ARRAY_TYPE
              && !(decl && !*decl)
              && !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
-                  && mem_size && tree_fits_uhwi_p (*mem_size)
+                  && tree_fits_uhwi_p (*mem_size)
                   && tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
            return NULL_TREE;
 
@@ -11496,7 +11505,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
              && TREE_CODE (TREE_TYPE (TREE_TYPE (rhs1))) == ARRAY_TYPE
              && !(decl && !*decl)
              && !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
-                  && mem_size && tree_fits_uhwi_p (*mem_size)
+                  && tree_fits_uhwi_p (*mem_size)
                   && tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
            return NULL_TREE;
 
@@ -11530,8 +11539,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
   if (TREE_CODE (array) == STRING_CST)
     {
       *ptr_offset = fold_convert (sizetype, offset);
-      if (mem_size)
-       *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
+      *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
       if (decl)
        *decl = NULL_TREE;
       gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (array)))
@@ -11561,7 +11569,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 
       base_off = wioff.to_uhwi ();
       unsigned HOST_WIDE_INT fieldoff = 0;
-      init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array,
+      init = fold_ctor_reference (TREE_TYPE (arg), init, base_off, 0, array,
                                  &fieldoff);
       HOST_WIDE_INT cstoff;
       if (!base_off.is_constant (&cstoff))
@@ -11580,17 +11588,11 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 
   *ptr_offset = offset;
 
-  tree eltype = TREE_TYPE (init);
-  tree initsize = TYPE_SIZE_UNIT (eltype);
-  if (mem_size)
-    *mem_size = initsize;
-
-  if (decl)
-    *decl = array;
+  tree inittype = TREE_TYPE (init);
 
   if (TREE_CODE (init) == INTEGER_CST
       && (TREE_CODE (TREE_TYPE (array)) == INTEGER_TYPE
-         || TYPE_MAIN_VARIANT (eltype) == char_type_node))
+         || TYPE_MAIN_VARIANT (inittype) == char_type_node))
     {
       /* For a reference to (address of) a single constant character,
         store the native representation of the character in CHARBUF.
@@ -11602,17 +11604,49 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
       int len = native_encode_expr (init, charbuf, sizeof charbuf, 0);
       if (len > 0)
        {
-         /* Construct a string literal with elements of ELTYPE and
+         /* Construct a string literal with elements of INITTYPE and
             the representation above.  Then strip
             the ADDR_EXPR (ARRAY_REF (...)) around the STRING_CST.  */
-         init = build_string_literal (len, (char *)charbuf, eltype);
+         init = build_string_literal (len, (char *)charbuf, inittype);
          init = TREE_OPERAND (TREE_OPERAND (init, 0), 0);
        }
     }
 
+  tree initsize = TYPE_SIZE_UNIT (inittype);
+
+  if (TREE_CODE (init) == CONSTRUCTOR && initializer_zerop (init))
+    {
+      /* Fold an empty/zero constructor for an implicitly initialized
+        object or subobject into the empty string.  */
+
+      /* Determine the character type from that of the original
+        expression.  */
+      tree chartype = argtype;
+      if (POINTER_TYPE_P (chartype))
+       chartype = TREE_TYPE (chartype);
+      while (TREE_CODE (chartype) == ARRAY_TYPE)
+       chartype = TREE_TYPE (chartype);
+      /* Convert a char array to an empty STRING_CST having an array
+        of the expected type.  */
+      if (!initsize)
+         initsize = integer_zero_node;
+
+      unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize);
+      init = build_string_literal (size ? 1 : 0, "", chartype, size);
+      init = TREE_OPERAND (init, 0);
+      init = TREE_OPERAND (init, 0);
+
+      *ptr_offset = integer_zero_node;
+    }
+
+  if (decl)
+    *decl = array;
+
   if (TREE_CODE (init) != STRING_CST)
     return NULL_TREE;
 
+  *mem_size = initsize;
+
   gcc_checking_assert (tree_to_shwi (initsize) >= TREE_STRING_LENGTH (init));
 
   return init;
index d576b0842f9e8f2de9bdca0050b0804f4187a9a3..fcffb9802b791bec4cd06af3f6beddc094d18a71 100644 (file)
@@ -759,11 +759,13 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
       dest_align = get_pointer_alignment (dest);
       if (tree_fits_uhwi_p (len)
          && compare_tree_int (len, MOVE_MAX) <= 0
-         /* ???  Don't transform copies from strings with known length this
-            confuses the tree-ssa-strlen.c.  This doesn't handle
-            the case in gcc.dg/strlenopt-8.c which is XFAILed for that
-            reason.  */
-         && !c_strlen (src, 2)
+         /* FIXME: Don't transform copies from strings with known length.
+            Until GCC 9 this prevented a case in gcc.dg/strlenopt-8.c
+            from being handled, and the case was XFAILed for that reason.
+            Now that it is handled and the XFAIL removed, as soon as other
+            strlenopt tests that rely on it for passing are adjusted, this
+            hack can be removed.  */
+         && !c_strlen (src, 1)
          && !((tmp_str = c_getstr (src, &tmp_len)) != NULL
               && memchr (tmp_str, 0, tmp_len) == NULL))
        {
@@ -6969,12 +6971,15 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
                                      from_decl, suboff);
        }
     }
-  /* Memory not explicitly mentioned in constructor is 0.  */
-  return type ? build_zero_cst (type) : NULL_TREE;
+
+  if (!type)
+    return NULL_TREE;
+
+  return build_zero_cst (type);
 }
 
 /* CTOR is value initializing memory.  Fold a reference of TYPE and
-   bit size POLY_SIZE to the memory at bit POLY_OFFSET.  When SIZE
+   bit size POLY_SIZE to the memory at bit POLY_OFFSET.  When POLY_SIZE
    is zero, attempt to fold a reference to the entire subobject
    which OFFSET refers to.  This is used when folding accesses to
    string members of aggregates.  When non-null, set *SUBOFF to
index 64175f258ae73a08c38d8740df172ead9cad4d43..cbfc47894dc5619140cf4a1e44c07f20b50209c9 100644 (file)
@@ -1678,7 +1678,8 @@ maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict,
   if (!warn_array_bounds)
     return false;
 
-  if (ref.ref && TREE_NO_WARNING (ref.ref))
+  if (TREE_NO_WARNING (ref.ptr)
+      || (ref.ref && TREE_NO_WARNING (ref.ref)))
     return false;
 
   if (EXPR_HAS_LOCATION (ref.ptr))
index 67ff3dcc3c32fbf219f7d91240260191642780f4..a7c4ec33d418788d98e0d5729e2069f76d76d1e7 100644 (file)
@@ -1,3 +1,11 @@
+2019-08-22  Martin Sebor  <msebor@redhat.com>
+
+       PR middle-end/91490
+       * c-c++-common/Warray-bounds-7.c: New test.
+       * gcc.dg/Warray-bounds-39.c: Expect either -Warray-bounds or
+       -Wstringop-overflow.
+       * gcc.dg/strlenopt-78.c: New test.
+
 2019-08-22  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * gcc.target/i386/minmax-4.c: Add -mno-stackrealign to dg-options.
diff --git a/gcc/testsuite/c-c++-common/Warray-bounds-7.c b/gcc/testsuite/c-c++-common/Warray-bounds-7.c
new file mode 100644 (file)
index 0000000..668e809
--- /dev/null
@@ -0,0 +1,107 @@
+/* PR middle-end/91490 - bogus argument missing terminating nul warning
+   on strlen of a flexible array member
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" } */
+
+#define INT_MAX       __INT_MAX__
+#define PTRDIFF_MAX   __PTRDIFF_MAX__
+#define SIZE_MAX      __SIZE_MAX__
+
+struct A0 { char n, a[0]; };
+struct A1 { char n, a[1]; };
+struct Ax { char n, a[]; };
+
+const struct A0 a0 = { };
+const struct A0 a0_0 = { 0 };
+const struct A0 a0_0_ = { 0, { } };
+
+const struct A0 a1 = { };
+const struct A0 a1_0 = { 0 };
+const struct A0 a1_0_ = { 0, { } };
+
+const struct Ax ax= { };
+const struct Ax ax_0 = { 0 };
+const struct Ax ax_0_ = { 0, { } };
+
+void sink (unsigned);
+
+#define T(x)   sink (__builtin_strlen (x))
+
+void test_zero_length_array (void)
+{
+  T (a0.a);                   // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a0.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
+
+  T (a0_0.a);                 // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+
+  T (a0_0_.a);                // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (a0_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_one_element_array (void)
+{
+  T (a1.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (a1.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
+
+  T (a1_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+
+  T (a1_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (a1_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_flexible_array_member (void)
+{
+  T (ax.a);                   // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a - 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + 1);               // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + 9);               // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + INT_MAX);         // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + PTRDIFF_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+  T (ax.a + SIZE_MAX);        // { dg-warning "\\\[-Warray-bounds" }
+
+  T (ax_0.a);                 // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a - 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + 1);             // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + 9);             // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + INT_MAX);       // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + PTRDIFF_MAX);   // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0.a + SIZE_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+
+  T (ax_0_.a);                // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a - 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + 1);            // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + 9);            // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + INT_MAX);      // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + PTRDIFF_MAX);  // { dg-warning "\\\[-Warray-bounds" }
+  T (ax_0_.a + SIZE_MAX);     // { dg-warning "\\\[-Warray-bounds" }
+}
+
index 6a441c73e01ce3a462caa3611ea03c8ebda8e303..ca42af86cd4ef6f8705b7d1ba32ea7e30e9c282c 100644 (file)
@@ -21,65 +21,65 @@ char d[4];
 
 void* test_memcpy_s0_1 (void *d)
 {
-  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_s0_2 (void *d)
 {
-  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_s0_0_1 (void *d)
 {
-  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_s0_0_2 (void *d)
 {
-  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 
 void* test_memcpy_s0_1_1 (void *d)
 {
-  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_s0_1_2 (void *d)
 {
-  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 
 void* test_memcpy_s1_0_1 (void *d)
 {
-  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_s1_0_2 (void *d)
 {
-  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 
 void* test_memmove_s0_1 (void *d)
 {
-  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds" } */
+  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memmove_s0_2 (void *d)
 {
-  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds" } */
+  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memmove_s0_0_1 (void *d)
 {
-  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds" } */
+  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memmove_s0_0_2 (void *d)
 {
-  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds" } */
+  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 
@@ -92,57 +92,57 @@ const struct Empty e1_0[1][0] = { };
 
 void* test_memcpy_e_1 (void *d)
 {
-  return memcpy (d, &e, 1);       /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, &e, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_e0_1 (void *d)
 {
-  return memcpy (d, e0, 1);       /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, e0, 1);       /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_e0_0_1 (void *d)
 {
-  return memcpy (d, e0_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, e0_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_e0_1_1 (void *d)
 {
-  return memcpy (d, e0_1, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, e0_1, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 void* test_memcpy_e1_0_1 (void *d)
 {
-  return memcpy (d, e1_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+  return memcpy (d, e1_0, 1);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 
 char* test_strcpy_s0 (char *d)
 {
-  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 char* test_strcpy_s0_0 (char *d)
 {
-  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */
 }
 
 
 char* test_strncpy_s0_1 (char *d)
 {
-  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 char* test_strncpy_s0_2 (char *d)
 {
-  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
 }
 
 char* test_strncpy_s0_0_1 (char *d)
 {
-  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */
 }
 
 char* test_strncpy_s0_0_2 (char *d)
 {
-  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr88991" { xfail *-*-* } } */
 }
diff --git a/gcc/testsuite/gcc.dg/strlenopt-78.c b/gcc/testsuite/gcc.dg/strlenopt-78.c
new file mode 100644 (file)
index 0000000..c028723
--- /dev/null
@@ -0,0 +1,166 @@
+/* PR middle-end/91490 - bogus argument missing terminating nul warning
+   on strlen of a flexible array member
+   Verify that strlen calls with a flexible array member (and its common
+   forms) of declaraed objects are folded.
+   { dg-do compile }
+   { dg-options "-Wall -fdump-tree-gimple" } */
+
+#include "strlenopt.h"
+
+extern void* memchr (const void*, int, size_t);
+
+struct A1 { char n, a[1]; };
+struct A2 { char n, a[2]; };
+struct A3 { char n, a[3]; };
+struct Ax { char n, a[]; };
+
+const struct A1 a1_0 = { 0 };
+const struct A1 a1_0_ = { 0, { } };
+const struct A1 a1_0_0 = { 0, { 0 } };
+
+const struct A2 a2_1_ = { 1, { } };
+const struct A2 a2_1_1 = { 1, { 1 } };
+const struct A2 a2_1_1_0 = { 1, { 1, 0 } };
+
+const struct A3 aa3_1_[2] = { { 1 } };
+
+const struct Ax ax = { 3, { 3, 2, 1, 0 } };
+
+struct BxA1 { int n; struct A1 a[]; };
+struct BxA2 { int n; struct A2 a[]; };
+
+const struct BxA2 bx = { 2, { { 2, { 2, 1 } }, { 2, { 1, 0 } } } };
+
+#if 0
+
+// Not implemented yet.
+
+int mchr1, mchr1__, mchr1_0, mchr2_1, mchr2, mchr2_1_0, mchrax, mchrbx;
+
+void test_memchr_flexarray (void)
+{
+  mchr1 = 0 != memchr (&a1_0, '1', sizeof a1_0);
+  mchr1__ = 0 != memchr (&a1_0_, '2', sizeof a1_0_);
+  mchr1_0 = 0 != memchr (&a1_0_0, '3', sizeof a1_0_0);
+
+  mchr2 = 0 != memchr (&a2_1_, '4', sizeof a2_1_);
+  mchr2_1 = 0 != memchr (&a2_1_1, '\001', sizeof a2_1_1);
+  mchr2_1_0 = 0 != memchr (&a2_1_1_0, '\001', sizeof a2_1_1_0);
+
+  mchrax = (const char*)&ax + sizeof ax - 1 == memchr (&ax, '\001', sizeof ax);
+  mchrbx = (const char*)&bx + sizeof bx - 1 == memchr (&bx, '\001', sizeof bx);
+}
+
+#endif
+
+
+int schr1, schr1__, schr1_0, schr2_1, schr2, schr2_1_0, schrax, schrbx;
+
+void test_strchr_flexarray (void)
+{
+  schr1 = 0 != strchr (a1_0.a, '1');
+  schr1__ = 0 != strchr (a1_0_.a, '2');
+  schr1_0 = 0 != strchr (a1_0_0.a, '3');
+
+  schr2 = 0 != strchr (a2_1_.a, '4');
+  schr2_1 = 0 != strchr (a2_1_1.a, '\001');
+  schr2_1_0 = 0 != strchr (a2_1_1_0.a, '\001');
+
+  schrax = 0 != strchr (ax.a, '\001');
+  schrbx = 0 != strchr (bx.a[1].a, '\0');
+
+  /* { dg-final { scan-tree-dump "schr1 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "schr1__ = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "schr1_0 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "schr2 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "schr2_1 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "schr2_1_0 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "schrax = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "schrbx = 1;" "gimple" } } */
+}
+
+
+int scmp1, scmp1__, scmp1_0, scmp2_1, scmp2, scmp2_1_0, scmpax, scmpbx;
+
+void test_strcmp_flexarray (void)
+{
+  scmp1 = 0 == strcmp (a1_0.a, "1");
+  scmp1__ = 0 == strcmp (a1_0_.a, "2");
+  scmp1_0 = 0 == strcmp (a1_0_0.a, "3");
+
+  scmp2 = 0 == strcmp (a2_1_.a, "4");
+  scmp2_1 = 0 == strcmp (a2_1_1.a, "\001");
+  scmp2_1_0 = 0 == strcmp (a2_1_1_0.a, "\001");
+
+  scmpax = 0 == strcmp (ax.a, "\003\002\001");
+  scmpbx = 0 == strcmp (bx.a[1].a, "\001");
+
+  /* { dg-final { scan-tree-dump "scmp1 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "scmp1__ = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "scmp1_0 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "scmp2 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "scmp2_1 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "scmp2_1_0 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "scmpax = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "scmpbx = 1;" "gimple" } } */
+}
+
+
+int len1, len1__, len1_0, len2_1, len2, len2_1_0, lenax, lenbx;
+
+void test_strlen_flexarray (void)
+{
+  len1 = strlen (a1_0.a);
+  len1__ = strlen (a1_0_.a);
+  len1_0 = strlen (a1_0_0.a);
+
+  len2 = strlen (a2_1_.a);
+  len2_1 = strlen (a2_1_1.a);
+  len2_1_0 = strlen (a2_1_1_0.a);
+
+  lenax = strlen (ax.a);
+  lenbx = strlen (bx.a[1].a);
+
+  /* { dg-final { scan-tree-dump "len1 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "len1__ = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "len1_0 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "len2 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "len2_1 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "len2_1_0 = 1;" "gimple" } }
+     { dg-final { scan-tree-dump "lenax = 3;" "gimple" } }
+     { dg-final { scan-tree-dump "lenbx = 1;" "gimple" } } */
+}
+
+
+int schraa3, scmpaa3, lenaa3;
+
+void test_trailing_array_empty_init (void)
+{
+  schraa3 = ((aa3_1_[0].a == strchr (aa3_1_[0].a, 0))
+            + (aa3_1_[1].a == strchr (aa3_1_[1].a, 0)));
+
+  scmpaa3 = strcmp (aa3_1_[0].a, aa3_1_[1].a);
+  lenaa3 = strlen (aa3_1_[0].a) + strlen (aa3_1_[1].a);
+
+  /* { dg-final { scan-tree-dump "schraa3 = 2;" "gimple" } }
+     { dg-final { scan-tree-dump "scmpaa3 = 0;" "gimple" } }
+     { dg-final { scan-tree-dump "lenaa3 = 0;" "gimple" } }  */
+}
+
+union U4 { char a[4]; int i; };
+const union U4 u4[2] = { { "123" } };
+
+int ulen0, ulen1;
+
+void test_union_init (void)
+{
+  ulen0 = strlen (u4[0].a);
+  ulen1 = strlen (u4[1].a);
+
+  /* { dg-final { scan-tree-dump "ulen0 = 3;" "gimple" } }
+     { dg-final { scan-tree-dump "ulen1 = 0;" "gimple" } } */
+}
+
+/* { dg-final { scan-tree-dump-not "strchr *\\(" "gimple" } }
+   { dg-final { scan-tree-dump-not "strcmp *\\(" "gimple" } }
+   { dg-final { scan-tree-dump-not "strlen *\\(" "gimple" } } */
index ae292281b1f53dc2181dc63a31d7f3c969fe415f..613efa5f2b0412e6d272aea7b30e165cce4556d3 100644 (file)
@@ -11872,18 +11872,23 @@ build_alloca_call_expr (tree size, unsigned int align, HOST_WIDE_INT max_size)
     }
 }
 
-/* Create a new constant string literal consisting of elements of type
-   ELTYPE and return a tree node representing char* pointer to it as
-   an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)).  The STRING_CST value is
-   the LEN bytes at STR (the representation of the string, which may
+/* Create a new constant string literal of type ELTYPE[SIZE] (or LEN
+   if SIZE == -1) and return a tree node representing char* pointer to
+   it as an ADDR_EXPR (ARRAY_REF (ELTYPE, ...)).  The STRING_CST value
+   is the LEN bytes at STR (the representation of the string, which may
    be wide).  */
 
 tree
 build_string_literal (int len, const char *str,
-                     tree eltype /* = char_type_node */)
+                     tree eltype /* = char_type_node */,
+                     unsigned HOST_WIDE_INT size /* = -1 */)
 {
   tree t = build_string (len, str);
-  tree index = build_index_type (size_int (len - 1));
+  /* Set the maximum valid index based on the string length or SIZE.  */
+  unsigned HOST_WIDE_INT maxidx
+    = (size == HOST_WIDE_INT_M1U ? len : size) - 1;
+
+  tree index = build_index_type (size_int (maxidx));
   eltype = build_type_variant (eltype, 1, 0);
   tree type = build_array_type (eltype, index);
   TREE_TYPE (t) = type;
index 37f6d57c03481d4e2ad8fe4c3f8b6fa4322f206a..fc85572dffa835debf0f11c34921911b780e4dc7 100644 (file)
@@ -4418,7 +4418,8 @@ extern tree build_call_expr_internal_loc_array (location_t, enum internal_fn,
 extern tree maybe_build_call_expr_loc (location_t, combined_fn, tree,
                                       int, ...);
 extern tree build_alloca_call_expr (tree, unsigned int, HOST_WIDE_INT);
-extern tree build_string_literal (int, const char *, tree = char_type_node);
+extern tree build_string_literal (int, const char *, tree = char_type_node,
+                                 unsigned HOST_WIDE_INT = HOST_WIDE_INT_M1U);
 
 /* Construct various nodes representing data types.  */