gimple-fold.h (get_range_strlen): Update prototype.
[gcc.git] / gcc / builtins.c
index 5f00208ff090cf8afa3eaa30e1ffcdc063def20c..28155b8c0aa8678bd252685143479042da6f7728 100644 (file)
@@ -1,5 +1,5 @@
 /* Expand builtin functions.
-   Copyright (C) 1988-2018 Free Software Foundation, Inc.
+   Copyright (C) 1988-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -126,10 +126,11 @@ static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, scalar_int_mode);
 static rtx expand_builtin_memchr (tree, rtx);
 static rtx expand_builtin_memcpy (tree, rtx);
 static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
-                                           rtx target, tree exp, int endp);
+                                           rtx target, tree exp,
+                                           memop_ret retmode);
 static rtx expand_builtin_memmove (tree, rtx);
 static rtx expand_builtin_mempcpy (tree, rtx);
-static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, int);
+static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret);
 static rtx expand_builtin_strcat (tree, rtx);
 static rtx expand_builtin_strcpy (tree, rtx);
 static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx);
@@ -565,14 +566,49 @@ warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
 
 /* If EXP refers to an unterminated constant character array return
    the declaration of the object of which the array is a member or
-   element.  Otherwise return null.  */
+   element and if SIZE is not null, set *SIZE to the size of
+   the unterminated array and set *EXACT if the size is exact or
+   clear it otherwise.  Otherwise return null.  */
 
 tree
-unterminated_array (tree exp)
-{
-  tree nonstr = NULL;
-  c_strlen (exp, 1, &nonstr);
-  return nonstr;
+unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
+{
+  /* C_STRLEN will return NULL and set DECL in the info
+     structure if EXP references a unterminated array.  */
+  c_strlen_data lendata = { };
+  tree len = c_strlen (exp, 1, &lendata);
+  if (len == NULL_TREE && lendata.minlen && lendata.decl)
+     {
+       if (size)
+       {
+         len = lendata.minlen;
+         if (lendata.off)
+           {
+             /* Constant offsets are already accounted for in LENDATA.MINLEN,
+                but not in a SSA_NAME + CST expression.  */
+             if (TREE_CODE (lendata.off) == INTEGER_CST)
+               *exact = true;
+             else if (TREE_CODE (lendata.off) == PLUS_EXPR
+                      && TREE_CODE (TREE_OPERAND (lendata.off, 1)) == INTEGER_CST)
+               {
+                 /* Subtract the offset from the size of the array.  */
+                 *exact = false;
+                 tree temp = TREE_OPERAND (lendata.off, 1);
+                 temp = fold_convert (ssizetype, temp);
+                 len = fold_build2 (MINUS_EXPR, ssizetype, len, temp);
+               }
+             else
+               *exact = false;
+           }
+         else
+           *exact = true;
+
+         *size = len;
+       }
+       return lendata.decl;
+     }
+
+  return NULL_TREE;
 }
 
 /* Compute the length of a null-terminated character string or wide
@@ -592,10 +628,12 @@ unterminated_array (tree exp)
    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.
+   Additional information about the string accessed may be recorded
+   in DATA.  For example, if SRC 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
+   than what a C strlen call would return.
 
    ELTSIZE is 1 for normal single byte character strings, and 2 or
    4 for wide characer strings.  ELTSIZE is by default 1.
@@ -603,8 +641,15 @@ unterminated_array (tree exp)
    The value returned is of type `ssizetype'.  */
 
 tree
-c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
+c_strlen (tree src, 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
+     each time we want to use it.  */
+  c_strlen_data local_strlen_data = { };
+  if (!data)
+    data = &local_strlen_data;
+
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
   STRIP_NOPS (src);
   if (TREE_CODE (src) == COND_EXPR
@@ -612,15 +657,15 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
     {
       tree len1, len2;
 
-      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
-      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, nonstr, eltsize);
+      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
+      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, data, eltsize);
       if (tree_int_cst_equal (len1, len2))
        return len1;
     }
 
   if (TREE_CODE (src) == COMPOUND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
-    return c_strlen (TREE_OPERAND (src, 1), only_value, nonstr, eltsize);
+    return c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
 
   location_t loc = EXPR_LOC_OR_LOC (src, input_location);
 
@@ -666,13 +711,16 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
         start searching for it.  */
       unsigned len = string_length (ptr, eltsize, strelts);
 
-      /* Return when an embedded null character is found or none at all.  */
+      /* Return when an embedded null character is found or none at all.
+        In the latter case, set the DECL/LEN field in the DATA structure
+        so that callers may examine them.  */
       if (len + 1 < strelts)
        return NULL_TREE;
       else if (len >= maxelts)
        {
-         if (nonstr && decl)
-           *nonstr = decl;
+         data->decl = decl;
+         data->off = byteoff;
+         data->minlen = ssize_int (len);
          return NULL_TREE;
        }
 
@@ -685,11 +733,14 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
         of the string subtract the offset from the length of the string,
         and return that.  Otherwise the length is zero.  Take care to
         use SAVE_EXPR in case the OFFSET has side-effects.  */
-      tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff) : byteoff;
-      offsave = fold_convert (ssizetype, offsave);
+      tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff)
+                                                : byteoff;
+      offsave = fold_convert_loc (loc, sizetype, offsave);
       tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave,
-                                     build_int_cst (ssizetype, len));
-      tree lenexp = size_diffop_loc (loc, ssize_int (len), offsave);
+                                     size_int (len));
+      tree lenexp = fold_build2_loc (loc, MINUS_EXPR, sizetype, size_int (len),
+                                    offsave);
+      lenexp = fold_convert_loc (loc, ssizetype, lenexp);
       return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp,
                              build_zero_cst (ssizetype));
     }
@@ -737,11 +788,13 @@ c_strlen (tree src, int only_value, tree *nonstr, unsigned eltsize)
                                strelts - eltoff);
 
   /* Don't know what to return if there was no zero termination.
-     Ideally this would turn into a gcc_checking_assert over time.  */
+     Ideally this would turn into a gcc_checking_assert over time.
+     Set DECL/LEN so callers can examine them.  */
   if (len >= maxelts - eltoff)
     {
-      if (nonstr && decl)
-       *nonstr = decl;
+      data->decl = decl;
+      data->off = byteoff;
+      data->minlen = ssize_int (len);
       return NULL_TREE;
     }
 
@@ -1088,8 +1141,11 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
          emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
          emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
-         emit_move_insn (hard_frame_pointer_rtx, fp);
+         /* Restore the frame pointer and stack pointer.  We must use a
+            temporary since the setjmp buffer may be a local.  */
+         fp = copy_to_reg (fp);
          emit_stack_restore (SAVE_NONLOCAL, stack);
+         emit_move_insn (hard_frame_pointer_rtx, fp);
 
          emit_use (hard_frame_pointer_rtx);
          emit_use (stack_pointer_rtx);
@@ -1232,9 +1288,11 @@ expand_builtin_nonlocal_goto (tree exp)
       emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
       emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
-      /* Restore frame pointer for containing function.  */
-      emit_move_insn (hard_frame_pointer_rtx, r_fp);
+      /* Restore the frame pointer and stack pointer.  We must use a
+        temporary since the setjmp buffer may be a local.  */
+      r_fp = copy_to_reg (r_fp);
       emit_stack_restore (SAVE_NONLOCAL, r_sp);
+      emit_move_insn (hard_frame_pointer_rtx, r_fp);
 
       /* USE of hard_frame_pointer_rtx added for consistency;
         not clear if really needed.  */
@@ -3023,9 +3081,10 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
   tree maxobjsize = max_object_size ();
   tree func = get_callee_fndecl (exp);
 
-  tree len = c_strlen (src, 0);
   /* FIXME: Change c_strlen() to return sizetype instead of ssizetype
      so these conversions aren't necessary.  */
+  c_strlen_data lendata = { };
+  tree len = c_strlen (src, 0, &lendata, 1);
   if (len)
     len = fold_convert_loc (loc, TREE_TYPE (bound), len);
 
@@ -3039,7 +3098,43 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
                         exp, func, bound, maxobjsize))
          TREE_NO_WARNING (exp) = true;
 
+      bool exact = true;
       if (!len || TREE_CODE (len) != INTEGER_CST)
+       {
+         /* Clear EXACT if LEN may be less than SRC suggests,
+            such as in
+              strnlen (&a[i], sizeof a)
+            where the value of i is unknown.  Unless i's value is
+            zero, the call is unsafe because the bound is greater. */
+         lendata.decl = unterminated_array (src, &len, &exact);
+         if (!lendata.decl)
+           return NULL_RTX;
+       }
+
+      if (lendata.decl
+         && !TREE_NO_WARNING (exp)
+         && ((tree_int_cst_lt (len, bound))
+             || !exact))
+       {
+         location_t warnloc
+           = expansion_point_location_if_in_system_header (loc);
+
+         if (warning_at (warnloc, OPT_Wstringop_overflow_,
+                         exact
+                         ? G_("%K%qD specified bound %E exceeds the size %E "
+                              "of unterminated array")
+                         : G_("%K%qD specified bound %E may exceed the size "
+                              "of at most %E of unterminated array"),
+                         exp, func, bound, len))
+           {
+             inform (DECL_SOURCE_LOCATION (lendata.decl),
+                     "referenced argument declared here");
+             TREE_NO_WARNING (exp) = true;
+             return NULL_RTX;
+           }
+       }
+
+      if (!len)
        return NULL_RTX;
 
       len = fold_build2_loc (loc, MIN_EXPR, size_type_node, len, bound);
@@ -3050,7 +3145,7 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_type rng = get_range_info (bound, &min, &max);
+  enum value_range_kind rng = get_range_info (bound, &min, &max);
   if (rng != VR_RANGE)
     return NULL_RTX;
 
@@ -3062,7 +3157,37 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
                     exp, func, min.to_uhwi (), max.to_uhwi (), maxobjsize))
       TREE_NO_WARNING (exp) = true;
 
+  bool exact = true;
   if (!len || TREE_CODE (len) != INTEGER_CST)
+    {
+      lendata.decl = unterminated_array (src, &len, &exact);
+      if (!lendata.decl)
+       return NULL_RTX;
+    }
+
+  if (lendata.decl
+      && !TREE_NO_WARNING (exp)
+      && (wi::ltu_p (wi::to_wide (len), min)
+         || !exact))
+    {
+      location_t warnloc
+       = expansion_point_location_if_in_system_header (loc);
+
+      if (warning_at (warnloc, OPT_Wstringop_overflow_,
+                     exact
+                     ? G_("%K%qD specified bound [%wu, %wu] exceeds "
+                          "the size %E of unterminated array")
+                     : G_("%K%qD specified bound [%wu, %wu] may exceed "
+                          "the size of at most %E of unterminated array"),
+                     exp, func, min.to_uhwi (), max.to_uhwi (), len))
+       {
+         inform (DECL_SOURCE_LOCATION (lendata.decl),
+                 "referenced argument declared here");
+         TREE_NO_WARNING (exp) = true;
+       }
+    }
+
+  if (lendata.decl)
     return NULL_RTX;
 
   if (wi::gtu_p (min, wi::to_wide (len)))
@@ -3108,7 +3233,7 @@ determine_block_size (tree len, rtx len_rtx,
   else
     {
       wide_int min, max;
-      enum value_range_type range_type = VR_UNDEFINED;
+      enum value_range_kind range_type = VR_UNDEFINED;
 
       /* Determine bounds from the type.  */
       if (tree_fits_uhwi_p (TYPE_MIN_VALUE (TREE_TYPE (len))))
@@ -3216,7 +3341,10 @@ check_access (tree exp, tree, tree, tree dstwrite,
             the upper bound given by MAXREAD add one to it for
             the terminating nul.  Otherwise, set it to one for
             the same reason, or to MAXREAD as appropriate.  */
-         get_range_strlen (srcstr, range);
+         c_strlen_data lendata = { };
+         get_range_strlen (srcstr, &lendata, /* eltsize = */ 1);
+         range[0] = lendata.minlen;
+         range[1] = lendata.maxbound;
          if (range[0] && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
            {
              if (maxread && tree_int_cst_le (maxread, range[0]))
@@ -3510,7 +3638,7 @@ compute_objsize (tree dest, int ostype)
              && INTEGRAL_TYPE_P (TREE_TYPE (off)))
            {
              wide_int min, max;
-             enum value_range_type rng = get_range_info (off, &min, &max);
+             enum value_range_kind rng = get_range_info (off, &min, &max);
 
              if (rng == VR_RANGE)
                {
@@ -3629,7 +3757,7 @@ expand_builtin_memcpy (tree exp, rtx target)
   check_memop_access (exp, dest, src, len);
 
   return expand_builtin_memory_copy_args (dest, src, len, target, exp,
-                                         /*endp=*/ 0);
+                                         /*retmode=*/ RETURN_BEGIN);
 }
 
 /* Check a call EXP to the memmove built-in for validity.
@@ -3654,10 +3782,7 @@ expand_builtin_memmove (tree exp, rtx)
 /* Expand a call EXP to the mempcpy builtin.
    Return NULL_RTX if we failed; the caller should emit a normal call,
    otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   mode MODE if that's convenient).  */
 
 static rtx
 expand_builtin_mempcpy (tree exp, rtx target)
@@ -3690,20 +3815,17 @@ expand_builtin_mempcpy (tree exp, rtx target)
     return NULL_RTX;
 
   return expand_builtin_mempcpy_args (dest, src, len,
-                                     target, exp, /*endp=*/ 1);
+                                     target, exp, /*retmode=*/ RETURN_END);
 }
 
 /* Helper function to do the actual work for expand of memory copy family
    functions (memcpy, mempcpy, stpcpy).  Expansing should assign LEN bytes
-   of memory from SRC to DEST and assign to TARGET if convenient.
-   If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   of memory from SRC to DEST and assign to TARGET if convenient.  Return
+   value is based on RETMODE argument.  */
 
 static rtx
 expand_builtin_memory_copy_args (tree dest, tree src, tree len,
-                                rtx target, tree exp, int endp)
+                                rtx target, tree exp, memop_ret retmode)
 {
   const char *src_str;
   unsigned int src_align = get_pointer_alignment (src);
@@ -3750,7 +3872,7 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
       dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                  builtin_memcpy_read_str,
                                  CONST_CAST (char *, src_str),
-                                 dest_align, false, endp);
+                                 dest_align, false, retmode);
       dest_mem = force_operand (XEXP (dest_mem, 0), target);
       dest_mem = convert_memory_address (ptr_mode, dest_mem);
       return dest_mem;
@@ -3761,9 +3883,10 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
 
   /* Copy word part most expediently.  */
   enum block_op_methods method = BLOCK_OP_NORMAL;
-  if (CALL_EXPR_TAILCALL (exp) && (endp == 0 || target == const0_rtx))
+  if (CALL_EXPR_TAILCALL (exp)
+      && (retmode == RETURN_BEGIN || target == const0_rtx))
     method = BLOCK_OP_TAILCALL;
-  if (endp == 1 && target != const0_rtx)
+  if (retmode == RETURN_END && target != const0_rtx)
     method = BLOCK_OP_NO_LIBCALL_RET;
   dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
                                     expected_align, expected_size,
@@ -3777,11 +3900,11 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
       dest_addr = convert_memory_address (ptr_mode, dest_addr);
     }
 
-  if (endp && target != const0_rtx)
+  if (retmode != RETURN_BEGIN && target != const0_rtx)
     {
       dest_addr = gen_rtx_PLUS (ptr_mode, dest_addr, len_rtx);
       /* stpcpy pointer to last byte.  */
-      if (endp == 2)
+      if (retmode == RETURN_END_MINUS_ONE)
        dest_addr = gen_rtx_MINUS (ptr_mode, dest_addr, const1_rtx);
     }
 
@@ -3790,21 +3913,19 @@ expand_builtin_memory_copy_args (tree dest, tree src, tree len,
 
 static rtx
 expand_builtin_mempcpy_args (tree dest, tree src, tree len,
-                            rtx target, tree orig_exp, int endp)
+                            rtx target, tree orig_exp, memop_ret retmode)
 {
   return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp,
-                                         endp);
+                                         retmode);
 }
 
 /* Expand into a movstr instruction, if one is available.  Return NULL_RTX if
    we failed, the caller should emit a normal call, otherwise try to
-   get the result in TARGET, if convenient.  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   get the result in TARGET, if convenient.
+   Return value is based on RETMODE argument.  */
 
 static rtx
-expand_movstr (tree dest, tree src, rtx target, int endp)
+expand_movstr (tree dest, tree src, rtx target, memop_ret retmode)
 {
   struct expand_operand ops[3];
   rtx dest_mem;
@@ -3815,25 +3936,26 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
 
   dest_mem = get_memory_rtx (dest, NULL);
   src_mem = get_memory_rtx (src, NULL);
-  if (!endp)
+  if (retmode == RETURN_BEGIN)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
       dest_mem = replace_equiv_address (dest_mem, target);
     }
 
-  create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
+  create_output_operand (&ops[0],
+                        retmode != RETURN_BEGIN ? target : NULL_RTX, Pmode);
   create_fixed_operand (&ops[1], dest_mem);
   create_fixed_operand (&ops[2], src_mem);
   if (!maybe_expand_insn (targetm.code_for_movstr, 3, ops))
     return NULL_RTX;
 
-  if (endp && target != const0_rtx)
+  if (retmode != RETURN_BEGIN && target != const0_rtx)
     {
       target = ops[0].value;
       /* movstr is supposed to set end to the address of the NUL
         terminator.  If the caller requested a mempcpy-like return value,
         adjust it.  */
-      if (endp == 1)
+      if (retmode == RETURN_END)
        {
          rtx tem = plus_constant (GET_MODE (target),
                                   gen_lowpart (GET_MODE (target), target), 1);
@@ -3922,7 +4044,7 @@ expand_builtin_strcpy_args (tree exp, tree dest, tree src, rtx target)
       return NULL_RTX;
     }
 
-  return expand_movstr (dest, src, target, /*endp=*/0);
+  return expand_movstr (dest, src, target, /*retmode=*/ RETURN_BEGIN);
 }
 
 /* Expand a call EXP to the stpcpy builtin.
@@ -3965,17 +4087,19 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
         compile-time, not an expression containing a string.  This is
         because the latter will potentially produce pessimized code
         when used to produce the return value.  */
-      tree nonstr = NULL_TREE;
+      c_strlen_data lendata = { };
       if (!c_getstr (src, NULL)
-         || !(len = c_strlen (src, 0, &nonstr, 1)))
-       return expand_movstr (dst, src, target, /*endp=*/2);
+         || !(len = c_strlen (src, 0, &lendata, 1)))
+       return expand_movstr (dst, src, target,
+                             /*retmode=*/ RETURN_END_MINUS_ONE);
 
-      if (nonstr && !TREE_NO_WARNING (exp))
-       warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, nonstr);
+      if (lendata.decl && !TREE_NO_WARNING (exp))
+       warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, lendata.decl);
 
       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
       ret = expand_builtin_mempcpy_args (dst, src, lenp1,
-                                        target, exp, /*endp=*/2);
+                                        target, exp,
+                                        /*retmode=*/ RETURN_END_MINUS_ONE);
 
       if (ret)
        return ret;
@@ -4009,7 +4133,8 @@ expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
            }
        }
 
-      return expand_movstr (dst, src, target, /*endp=*/2);
+      return expand_movstr (dst, src, target,
+                           /*retmode=*/ RETURN_END_MINUS_ONE);
     }
 }
 
@@ -4087,8 +4212,8 @@ check_strncat_sizes (tree exp, tree objsize)
 
   /* Try to determine the range of lengths that the source expression
      refers to.  */
-  tree lenrange[2];
-  get_range_strlen (src, lenrange);
+  c_strlen_data lendata = { };
+  get_range_strlen (src, &lendata, /* eltsize = */ 1);
 
   /* Try to verify that the destination is big enough for the shortest
      string.  */
@@ -4102,8 +4227,8 @@ check_strncat_sizes (tree exp, tree objsize)
     }
 
   /* Add one for the terminating nul.  */
-  tree srclen = (lenrange[0]
-                ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
+  tree srclen = (lendata.minlen
+                ? fold_build2 (PLUS_EXPR, size_type_node, lendata.minlen,
                                size_one_node)
                 : NULL_TREE);
 
@@ -4155,12 +4280,15 @@ expand_builtin_strncat (tree exp, rtx)
   tree slen = c_strlen (src, 1);
 
   /* Try to determine the range of lengths that the source expression
-     refers to.  */
-  tree lenrange[2];
-  if (slen)
-    lenrange[0] = lenrange[1] = slen;
-  else
-    get_range_strlen (src, lenrange);
+     refers to.  Since the lengths are only used for warning and not
+     for code generation disable strict mode below.  */
+  tree maxlen = slen;
+  if (!maxlen)
+    {
+      c_strlen_data lendata = { };
+      get_range_strlen (src, &lendata, /* eltsize = */ 1);
+      maxlen = lendata.maxbound;
+    }
 
   /* Try to verify that the destination is big enough for the shortest
      string.  First try to determine the size of the destination object
@@ -4168,8 +4296,8 @@ expand_builtin_strncat (tree exp, rtx)
   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
 
   /* Add one for the terminating nul.  */
-  tree srclen = (lenrange[0]
-                ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
+  tree srclen = (maxlen
+                ? fold_build2 (PLUS_EXPR, size_type_node, maxlen,
                                size_one_node)
                 : NULL_TREE);
 
@@ -4255,7 +4383,8 @@ expand_builtin_strncpy (tree exp, rtx target)
          dest_mem = get_memory_rtx (dest, len);
          store_by_pieces (dest_mem, tree_to_uhwi (len),
                           builtin_strncpy_read_str,
-                          CONST_CAST (char *, p), dest_align, false, 0);
+                          CONST_CAST (char *, p), dest_align, false,
+                          RETURN_BEGIN);
          dest_mem = force_operand (XEXP (dest_mem, 0), target);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
@@ -4400,7 +4529,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
          val_rtx = force_reg (val_mode, val_rtx);
          store_by_pieces (dest_mem, tree_to_uhwi (len),
                           builtin_memset_gen_str, val_rtx, dest_align,
-                          true, 0);
+                          true, RETURN_BEGIN);
        }
       else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
                                        dest_align, expected_align,
@@ -4423,7 +4552,8 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                  builtin_memset_read_str, &c, dest_align,
                                  true))
        store_by_pieces (dest_mem, tree_to_uhwi (len),
-                        builtin_memset_read_str, &c, dest_align, true, 0);
+                        builtin_memset_read_str, &c, dest_align, true,
+                        RETURN_BEGIN);
       else if (!set_storage_via_setmem (dest_mem, len_rtx,
                                        gen_int_mode (c, val_mode),
                                        dest_align, expected_align,
@@ -5850,6 +5980,7 @@ get_builtin_sync_mem (tree loc, machine_mode mode)
   scalar_int_mode addr_mode = targetm.addr_space.address_mode (addr_space);
 
   addr = expand_expr (loc, NULL_RTX, addr_mode, EXPAND_SUM);
+  addr = convert_memory_address (addr_mode, addr);
 
   /* Note that we explicitly do not want any alias information for this
      memory, so that we kill all other live memories.  Otherwise we don't
@@ -6027,7 +6158,7 @@ get_memmodel (tree exp)
 {
   rtx op;
   unsigned HOST_WIDE_INT val;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (input_location);
 
   /* If the parameter is not a constant, it's a run time value so we'll just
@@ -6103,7 +6234,7 @@ expand_builtin_atomic_compare_exchange (machine_mode mode, tree exp,
   enum memmodel success, failure;
   tree weak;
   bool is_weak;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (input_location);
 
   success = get_memmodel (CALL_EXPR_ARG (exp, 4));
@@ -6230,7 +6361,7 @@ expand_ifn_atomic_compare_exchange (gcall *call)
   enum memmodel success, failure;
   tree lhs;
   bool is_weak;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (gimple_location (call));
 
   success = get_memmodel (gimple_call_arg (call, 4));
@@ -6302,7 +6433,7 @@ expand_builtin_atomic_load (machine_mode mode, tree exp, rtx target)
   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
   if (is_mm_release (model) || is_mm_acq_rel (model))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_load%>");
@@ -6334,7 +6465,7 @@ expand_builtin_atomic_store (machine_mode mode, tree exp)
   if (!(is_mm_relaxed (model) || is_mm_seq_cst (model)
        || is_mm_release (model)))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_store%>");
@@ -6527,7 +6658,7 @@ expand_builtin_atomic_clear (tree exp)
 
   if (is_mm_consume (model) || is_mm_acquire (model) || is_mm_acq_rel (model))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_store%>");
@@ -8443,22 +8574,22 @@ fold_builtin_strlen (location_t loc, tree type, tree arg)
     return NULL_TREE;
   else
     {
-      tree nonstr = NULL_TREE;
-      tree len = c_strlen (arg, 0, &nonstr);
+      c_strlen_data lendata = { };
+      tree len = c_strlen (arg, 0, &lendata);
 
       if (len)
        return fold_convert_loc (loc, type, len);
 
-      if (!nonstr)
-       c_strlen (arg, 1, &nonstr);
+      if (!lendata.decl)
+       c_strlen (arg, 1, &lendata);
 
-      if (nonstr)
+      if (lendata.decl)
        {
          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);
+         warn_string_no_nul (loc, "strlen", arg, lendata.decl);
        }
 
       return NULL_TREE;
@@ -10075,7 +10206,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
      definition of the va_start macro (perhaps on the token for
      builtin) in a system header, so warnings will not be emitted.
      Use the location in real source code.  */
-  source_location current_location =
+  location_t current_location =
     linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
                                              NULL);