decl.c (start_decl): Improve error location.
[gcc.git] / gcc / tree-ssa-strlen.c
index 3fa5ef56f38e726276d9146e542aff324d4c8c27..55fba88e0f4f7377735d54bb6a79388c90435f15 100644 (file)
@@ -1,5 +1,5 @@
 /* String length optimization
-   Copyright (C) 2011-2018 Free Software Foundation, Inc.
+   Copyright (C) 2011-2019 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>
 
 This file is part of GCC.
@@ -1064,7 +1064,7 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
 
       if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
        return;
-      if (stmt_could_throw_p (last.stmt))
+      if (stmt_could_throw_p (cfun, last.stmt))
        return;
       gsi = gsi_for_stmt (last.stmt);
       unlink_stmt_vdef (last.stmt);
@@ -1121,67 +1121,23 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
   update_stmt (last.stmt);
 }
 
-/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
-   SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
-   a character array A[N] with unknown length bounded by N, and for
-   strnlen(), by min (N, BOUND).  */
+/* For an LHS that is an SSA_NAME that is the result of a strlen()
+   call, or when BOUND is non-null, of a strnlen() call, set LHS
+   range info to [0, min (MAX, BOUND)] when the range includes more
+   than one value and return LHS.  Otherwise, when the range
+   [MIN, MAX] is such that MIN == MAX, return the tree representation
+   of (MIN). The latter allows callers to fold suitable strnlen() calls
+   to constants.  */
 
-static tree
-maybe_set_strlen_range (tree lhs, tree src, tree bound)
+tree
+set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
 {
   if (TREE_CODE (lhs) != SSA_NAME
       || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
     return NULL_TREE;
 
-  if (TREE_CODE (src) == SSA_NAME)
-    {
-      gimple *def = SSA_NAME_DEF_STMT (src);
-      if (is_gimple_assign (def)
-         && gimple_assign_rhs_code (def) == ADDR_EXPR)
-       src = gimple_assign_rhs1 (def);
-    }
-
-  wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
   wide_int min = wi::zero (max.get_precision ());
 
-  if (TREE_CODE (src) == ADDR_EXPR)
-    {
-      /* The last array member of a struct can be bigger than its size
-        suggests if it's treated as a poor-man's flexible array member.  */
-      src = TREE_OPERAND (src, 0);
-      bool src_is_array = TREE_CODE (TREE_TYPE (src)) == ARRAY_TYPE;
-      if (src_is_array
-         && TREE_CODE (src) != MEM_REF
-         && !array_at_struct_end_p (src))
-       {
-         tree type = TREE_TYPE (src);
-         if (tree size = TYPE_SIZE_UNIT (type))
-           if (size && TREE_CODE (size) == INTEGER_CST)
-             max = wi::to_wide (size);
-
-         /* For strlen() the upper bound above is equal to
-            the longest string that can be stored in the array
-            (i.e., it accounts for the terminating nul.  For
-            strnlen() bump up the maximum by one since the array
-            need not be nul-terminated.  */
-         if (!bound && max != 0)
-           --max;
-       }
-      else
-       {
-         if (TREE_CODE (src) == COMPONENT_REF && !src_is_array)
-           src = TREE_OPERAND (src, 1);
-         if (DECL_P (src))
-           {
-             /* Handle the unlikely case of strlen (&c) where c is some
-                variable.  */
-             if (tree size = DECL_SIZE_UNIT (src))
-               if (TREE_CODE (size) == INTEGER_CST)
-                 max = wi::to_wide (size);
-           }
-       }
-    }
-
   if (bound)
     {
       /* For strnlen, adjust MIN and MAX as necessary.  If the bound
@@ -1200,12 +1156,12 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
       else if (TREE_CODE (bound) == SSA_NAME)
        {
          wide_int minbound, maxbound;
-         value_range_type rng = get_range_info (bound, &minbound, &maxbound);
+         value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
          if (rng == VR_RANGE)
            {
              /* For a bound in a known range, adjust the range determined
                 above as necessary.  For a bound in some anti-range or
-                in an unknown range, use the range determined above.  */
+                in an unknown range, use the range determined by callers.  */
              if (wi::ltu_p (minbound, min))
                min = minbound;
              if (wi::ltu_p (maxbound, max))
@@ -1221,6 +1177,79 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
   return lhs;
 }
 
+/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
+   SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
+   a character array A[N] with unknown length bounded by N, and for
+   strnlen(), by min (N, BOUND).  */
+
+static tree
+maybe_set_strlen_range (tree lhs, tree src, tree bound)
+{
+  if (TREE_CODE (lhs) != SSA_NAME
+      || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
+    return NULL_TREE;
+
+  if (TREE_CODE (src) == SSA_NAME)
+    {
+      gimple *def = SSA_NAME_DEF_STMT (src);
+      if (is_gimple_assign (def)
+         && gimple_assign_rhs_code (def) == ADDR_EXPR)
+       src = gimple_assign_rhs1 (def);
+    }
+
+  /* The longest string is PTRDIFF_MAX - 1 bytes including the final
+     NUL so that the difference between a pointer to just past it and
+     one to its beginning is positive.  */
+  wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2;
+
+  if (TREE_CODE (src) == ADDR_EXPR)
+    {
+      /* The last array member of a struct can be bigger than its size
+        suggests if it's treated as a poor-man's flexible array member.  */
+      src = TREE_OPERAND (src, 0);
+      if (TREE_CODE (src) != MEM_REF
+         && !array_at_struct_end_p (src))
+       {
+         tree type = TREE_TYPE (src);
+         tree size = TYPE_SIZE_UNIT (type);
+         if (size
+             && TREE_CODE (size) == INTEGER_CST
+             && !integer_zerop (size))
+           {
+             /* Even though such uses of strlen would be undefined,
+                avoid relying on arrays of arrays in case some genius
+                decides to call strlen on an unterminated array element
+                that's followed by a terminated one.  Likewise, avoid
+                assuming that a struct array member is necessarily
+                nul-terminated (the nul may be in the member that
+                follows).  In those cases, assume that the length
+                of the string stored in such an array is bounded
+                by the size of the enclosing object if one can be
+                determined.  */
+             tree base = get_base_address (src);
+             if (VAR_P (base))
+               {
+                 if (tree size = DECL_SIZE_UNIT (base))
+                   if (size
+                       && TREE_CODE (size) == INTEGER_CST
+                       && TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE)
+                     max = wi::to_wide (size);
+               }
+           }
+
+         /* For strlen() the upper bound above is equal to
+            the longest string that can be stored in the array
+            (i.e., it accounts for the terminating nul.  For
+            strnlen() bump up the maximum by one since the array
+            need not be nul-terminated.  */
+         if (!bound && max != 0)
+           --max;
+       }
+    }
+
+  return set_strlen_range (lhs, max, bound);
+}
+
 /* Handle a strlen call.  If strlen of the argument is known, replace
    the strlen call with the known value, otherwise remember that strlen
    of the argument is stored in the lhs SSA_NAME.  */
@@ -1856,7 +1885,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     cntrange[0] = cntrange[1] = wi::to_wide (cnt);
   else if (TREE_CODE (cnt) == SSA_NAME)
     {
-      enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
+      enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
       if (rng == VR_RANGE)
        ;
       else if (rng == VR_ANTI_RANGE)
@@ -1989,15 +2018,18 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     lenrange[0] = lenrange[1] = wi::shwi (~sidx, prec);
   else
     {
-      tree range[2];
-      get_range_strlen (src, range);
-      if (range[0] != NULL_TREE
-         && TREE_CODE (range[0]) == INTEGER_CST
-         && range[1] != NULL_TREE
-         && TREE_CODE (range[1]) == INTEGER_CST)
+      c_strlen_data lendata = { };
+      get_range_strlen (src, &lendata, /* eltsize = */1);
+      if (TREE_CODE (lendata.minlen) == INTEGER_CST
+         && TREE_CODE (lendata.maxbound) == INTEGER_CST)
        {
-         lenrange[0] = wi::to_wide (range[0], prec);
-         lenrange[1] = wi::to_wide (range[1], prec);
+         /* When LENDATA.MAXLEN is unknown, reset LENDATA.MINLEN
+            which stores the length of the shortest known string.  */
+         if (integer_all_onesp (lendata.maxlen))
+           lenrange[0] = wi::shwi (0, prec);
+         else
+           lenrange[0] = wi::to_wide (lendata.minlen, prec);
+         lenrange[1] = wi::to_wide (lendata.maxbound, prec);
        }
       else
        {
@@ -2114,6 +2146,13 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
       if (wi::to_wide (dstsize) != cntrange[1])
        return false;
 
+      /* Avoid warning for strncpy(a, b, N) calls where the following
+        equalities hold:
+          N == sizeof a && N == sizeof b */
+      if (tree srcsize = compute_objsize (src, 1))
+       if (wi::to_wide (srcsize) == cntrange[1])
+         return false;
+
       if (cntrange[0] == cntrange[1])
        return warning_at (callloc, OPT_Wstringop_truncation,
                           "%G%qD specified bound %E equals destination size",
@@ -2605,12 +2644,19 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
   if (endptr)
     dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
   else
-    dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                          TREE_TYPE (dst), unshare_expr (dst),
+    dst = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dst), dst,
                           fold_convert_loc (loc, sizetype,
                                             unshare_expr (dstlen)));
   dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
                                  GSI_SAME_STMT);
+  if (objsz)
+    {
+      objsz = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (objsz), objsz,
+                              fold_convert_loc (loc, TREE_TYPE (objsz),
+                                                unshare_expr (dstlen)));
+      objsz = force_gimple_operand_gsi (gsi, objsz, true, NULL_TREE, true,
+                                       GSI_SAME_STMT);
+    }
   if (dump_file && (dump_flags & TDF_DETAILS) != 0)
     {
       fprintf (dump_file, "Optimizing: ");
@@ -3253,7 +3299,7 @@ handle_char_store (gimple_stmt_iterator *gsi)
        {
          /* When overwriting a '\0' with a '\0', the store can be removed
             if we know it has been stored in the current function.  */
-         if (!stmt_could_throw_p (stmt) && si->writable)
+         if (!stmt_could_throw_p (cfun, stmt) && si->writable)
            {
              unlink_stmt_vdef (stmt);
              release_defs (stmt);
@@ -3682,7 +3728,7 @@ strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
                           if we don't have anything better.  */
                        wide_int min, max;
                        tree type = TREE_TYPE (lhs);
-                       enum value_range_type vr
+                       enum value_range_kind vr
                          = get_range_info (lhs, &min, &max);
                        if (vr == VR_VARYING
                            || (vr == VR_RANGE