diff mbox series

[v4,2/3,RFC] Provide more contexts for -Warray-bounds, -Wstringop-* warning messages due to code movements from compiler transformation (Part 2) [PR109071, PR85788, PR88771, PR106762, PR108770, PR115274, PR117179]

Message ID 20241105163132.1922052-3-qing.zhao@oracle.com
State New
Headers show
Series Provide more contexts for -Warray-bounds and -Wstringop-* warning messages | expand

Commit Message

Qing Zhao Nov. 5, 2024, 4:31 p.m. UTC
During array out-of-bound checking or -Wstringop-* warning checking, the
"move_history" that was attached to the gimple statement is used to form
a sequence of diagnostic events that are added to the corresponding rich
location to be used to report the warning message.

	PR tree-optimization/109071
	PR tree-optimization/85788
	PR tree-optimization/88771
	PR tree-optimization/106762
	PR tree-optimization/108770
	PR tree-optimization/115274
	PR tree-optimization/117179

gcc/ChangeLog:

	* Makefile.in (OBJS): Add move-history-rich-location.o.
	* gimple-array-bounds.cc (check_out_of_bounds_and_warn): Add
	one new parameter. Use rich location with details for warning_at.
	(array_bounds_checker::check_array_ref): Use rich location with
	ditails for warning_at.
	(array_bounds_checker::check_mem_ref): Add one new parameter.
	Use rich location with details for warning_at.
	(array_bounds_checker::check_addr_expr): Use rich location with
	move_history_diagnostic_path for warning_at.
	(array_bounds_checker::check_array_bounds): Call check_mem_ref with
	one more parameter.
	* gimple-array-bounds.h: Update prototype for check_mem_ref.
	* gimple-ssa-warn-restrict.cc (maybe_diag_access_bounds): Use
	rich location with details for warning_at.
        * gimple-ssa-warn-access.cc (warn_string_no_nul): Likewise.
        (maybe_warn_nonstring_arg): Likewise.
        (maybe_warn_for_bound): Likewise.
        (warn_for_access): Likewise.
        (check_access): Likewise.
        (pass_waccess::check_strncat): Likewise.
        (pass_waccess::maybe_check_access_sizes): Likewise.
	* move-history-rich-location.cc: New file.
	* move-history-rich-location.h: New file.

gcc/testsuite/ChangeLog:

	* gcc.dg/pr109071.c: New test.
	* gcc.dg/pr109071_1.c: New test.
	* gcc.dg/pr109071_2.c: New test.
	* gcc.dg/pr109071_3.c: New test.
	* gcc.dg/pr109071_4.c: New test.
        * gcc.dg/pr109071_5.c: New test.
        * gcc.dg/pr109071_6.c: New test.
---
 gcc/Makefile.in                   |   1 +
 gcc/gimple-array-bounds.cc        |  39 +++++----
 gcc/gimple-array-bounds.h         |   2 +-
 gcc/gimple-ssa-warn-access.cc     | 131 +++++++++++++++++-------------
 gcc/gimple-ssa-warn-restrict.cc   |  25 +++---
 gcc/move-history-rich-location.cc |  56 +++++++++++++
 gcc/move-history-rich-location.h  |  65 +++++++++++++++
 gcc/testsuite/gcc.dg/pr109071.c   |  43 ++++++++++
 gcc/testsuite/gcc.dg/pr109071_1.c |  36 ++++++++
 gcc/testsuite/gcc.dg/pr109071_2.c |  50 ++++++++++++
 gcc/testsuite/gcc.dg/pr109071_3.c |  42 ++++++++++
 gcc/testsuite/gcc.dg/pr109071_4.c |  41 ++++++++++
 gcc/testsuite/gcc.dg/pr109071_5.c |  33 ++++++++
 gcc/testsuite/gcc.dg/pr109071_6.c |  49 +++++++++++
 14 files changed, 530 insertions(+), 83 deletions(-)
 create mode 100644 gcc/move-history-rich-location.cc
 create mode 100644 gcc/move-history-rich-location.h
 create mode 100644 gcc/testsuite/gcc.dg/pr109071.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_5.c
 create mode 100644 gcc/testsuite/gcc.dg/pr109071_6.c

Comments

David Malcolm Nov. 5, 2024, 7:29 p.m. UTC | #1
On Tue, 2024-11-05 at 16:31 +0000, Qing Zhao wrote:
> During array out-of-bound checking or -Wstringop-* warning checking,
> the
> "move_history" that was attached to the gimple statement is used to
> form
> a sequence of diagnostic events that are added to the corresponding
> rich
> location to be used to report the warning message.


Thanks for the rewrite to use lazy_diagnostic_path; this looks good to
me FWIW.

Dave
Qing Zhao Nov. 5, 2024, 7:36 p.m. UTC | #2
> On Nov 5, 2024, at 14:29, David Malcolm <dmalcolm@redhat.com> wrote:
> 
> On Tue, 2024-11-05 at 16:31 +0000, Qing Zhao wrote:
>> During array out-of-bound checking or -Wstringop-* warning checking,
>> the
>> "move_history" that was attached to the gimple statement is used to
>> form
>> a sequence of diagnostic events that are added to the corresponding
>> rich
>> location to be used to report the warning message.
> 
> 
> Thanks for the rewrite to use lazy_diagnostic_path; this looks good to
> me FWIW.

The code is much cleaner after using lazy_diagnostic_path, thanks a lot for all your help.

Qing
> 
> Dave
>
diff mbox series

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 68677b6d90b..49aee4fb206 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1604,6 +1604,7 @@  OBJS = \
 	mcf.o \
 	mode-switching.o \
 	modulo-sched.o \
+	move-history-rich-location.o \
 	multiple_target.o \
 	omp-offload.o \
 	omp-expand.o \
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index ce1d14846d8..d5f6485dee0 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -17,6 +17,7 @@  You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define INCLUDE_MEMORY
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -31,6 +32,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "fold-const.h"
 #include "diagnostic-core.h"
+#include "move-history-rich-location.h"
 #include "intl.h"
 #include "tree-vrp.h"
 #include "alloc-pool.h"
@@ -262,6 +264,7 @@  get_up_bounds_for_array_ref (tree ref, tree *decl,
 
 static bool
 check_out_of_bounds_and_warn (location_t location, tree ref,
+			      gimple *stmt,
 			      tree low_sub_org, tree low_sub, tree up_sub,
 			      tree up_bound, tree up_bound_p1,
 			      const irange *vr,
@@ -275,12 +278,13 @@  check_out_of_bounds_and_warn (location_t location, tree ref,
   bool warned = false;
   *out_of_bound = false;
 
+  rich_location_with_details richloc (location, stmt);
   /* Empty array.  */
   if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
     {
       *out_of_bound = true;
       if (for_array_bound)
-	warned = warning_at (location, OPT_Warray_bounds_,
+	warned = warning_at (&richloc, OPT_Warray_bounds_,
 			     "array subscript %E is outside array"
 			     " bounds of %qT", low_sub_org, artype);
     }
@@ -299,7 +303,7 @@  check_out_of_bounds_and_warn (location_t location, tree ref,
 	{
 	  *out_of_bound = true;
 	  if (for_array_bound)
-	    warned = warning_at (location, OPT_Warray_bounds_,
+	    warned = warning_at (&richloc, OPT_Warray_bounds_,
 				 "array subscript [%E, %E] is outside "
 				 "array bounds of %qT",
 				 low_sub, up_sub, artype);
@@ -313,7 +317,7 @@  check_out_of_bounds_and_warn (location_t location, tree ref,
     {
       *out_of_bound = true;
       if (for_array_bound)
-	warned = warning_at (location, OPT_Warray_bounds_,
+	warned = warning_at (&richloc, OPT_Warray_bounds_,
 			     "array subscript %E is above array bounds of %qT",
 			     up_sub, artype);
     }
@@ -322,7 +326,7 @@  check_out_of_bounds_and_warn (location_t location, tree ref,
     {
       *out_of_bound = true;
       if (for_array_bound)
-	warned = warning_at (location, OPT_Warray_bounds_,
+	warned = warning_at (&richloc, OPT_Warray_bounds_,
 			     "array subscript %E is below array bounds of %qT",
 			     low_sub, artype);
     }
@@ -388,15 +392,16 @@  array_bounds_checker::check_array_ref (location_t location, tree ref,
 	}
     }
 
-  warned = check_out_of_bounds_and_warn (location, ref,
+  warned = check_out_of_bounds_and_warn (location, ref, stmt,
 					 low_sub_org, low_sub, up_sub,
 					 up_bound, up_bound_p1, &vr,
 					 ignore_off_by_one, warn_array_bounds,
 					 &out_of_bound);
 
+  rich_location_with_details richloc (location, stmt);
 
   if (!warned && sam == special_array_member::int_0)
-    warned = warning_at (location, OPT_Wzero_length_bounds,
+    warned = warning_at (&richloc, OPT_Wzero_length_bounds,
 			 (TREE_CODE (low_sub) == INTEGER_CST
 			  ? G_("array subscript %E is outside the bounds "
 			       "of an interior zero-length array %qT")
@@ -420,7 +425,7 @@  array_bounds_checker::check_array_ref (location_t location, tree ref,
       && DECL_NOT_FLEXARRAY (afield_decl))
     {
       bool warned1
-	= warning_at (location, OPT_Wstrict_flex_arrays,
+	= warning_at (&richloc, OPT_Wstrict_flex_arrays,
 		      "trailing array %qT should not be used as "
 		      "a flexible array member",
 		      artype);
@@ -478,6 +483,7 @@  array_bounds_checker::check_array_ref (location_t location, tree ref,
 
 bool
 array_bounds_checker::check_mem_ref (location_t location, tree ref,
+				     gimple *stmt,
 				     bool ignore_off_by_one)
 {
   if (warning_suppressed_p (ref, OPT_Warray_bounds_))
@@ -576,16 +582,17 @@  array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	}
     }
 
+  rich_location_with_details richloc (location, stmt);
   bool warned = false;
   if (lboob)
     {
       if (offrange[0] == offrange[1])
-	warned = warning_at (location, OPT_Warray_bounds_,
+	warned = warning_at (&richloc, OPT_Warray_bounds_,
 			     "array subscript %wi is outside array bounds "
 			     "of %qT",
 			     offrange[0].to_shwi (), reftype);
       else
-	warned = warning_at (location, OPT_Warray_bounds_,
+	warned = warning_at (&richloc, OPT_Warray_bounds_,
 			     "array subscript [%wi, %wi] is outside "
 			     "array bounds of %qT",
 			     offrange[0].to_shwi (),
@@ -599,8 +606,7 @@  array_bounds_checker::check_mem_ref (location_t location, tree ref,
 	   it were an untyped array of bytes.  */
 	backtype = build_array_type_nelts (unsigned_char_type_node,
 					   aref.sizrng[1].to_uhwi ());
-
-      warned = warning_at (location, OPT_Warray_bounds_,
+      warned = warning_at (&richloc, OPT_Warray_bounds_,
 			   "array subscript %<%T[%wi]%> is partly "
 			   "outside array bounds of %qT",
 			   axstype, offrange[0].to_shwi (), backtype);
@@ -623,7 +629,7 @@  array_bounds_checker::check_mem_ref (location_t location, tree ref,
     {
       HOST_WIDE_INT tmpidx = (aref.offmax[i] / eltsize).to_shwi ();
 
-      if (warning_at (location, OPT_Warray_bounds_,
+      if (warning_at (&richloc, OPT_Warray_bounds_,
 		      "intermediate array offset %wi is outside array bounds "
 		      "of %qT", tmpidx, reftype))
 	{
@@ -656,7 +662,7 @@  array_bounds_checker::check_addr_expr (location_t location, tree t,
 	  ignore_off_by_one = false;
 	}
       else if (TREE_CODE (t) == MEM_REF)
-	warned = check_mem_ref (location, t, ignore_off_by_one);
+	warned = check_mem_ref (location, t, stmt, ignore_off_by_one);
 
       if (warned)
 	suppress_warning (t, OPT_Warray_bounds_);
@@ -692,6 +698,7 @@  array_bounds_checker::check_addr_expr (location_t location, tree t,
   if (!mem_ref_offset (t).is_constant (&idx))
     return;
 
+  rich_location_with_details richloc (location, stmt);
   bool warned = false;
   idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
   if (idx < 0)
@@ -702,7 +709,7 @@  array_bounds_checker::check_addr_expr (location_t location, tree t,
 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
 	  fprintf (dump_file, "\n");
 	}
-      warned = warning_at (location, OPT_Warray_bounds_,
+      warned = warning_at (&richloc, OPT_Warray_bounds_,
 			   "array subscript %wi is below "
 			   "array bounds of %qT",
 			   idx.to_shwi (), TREE_TYPE (tem));
@@ -716,7 +723,7 @@  array_bounds_checker::check_addr_expr (location_t location, tree t,
 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
 	  fprintf (dump_file, "\n");
 	}
-      warned = warning_at (location, OPT_Warray_bounds_,
+      warned = warning_at (&richloc, OPT_Warray_bounds_,
 			   "array subscript %wu is above "
 			   "array bounds of %qT",
 			   idx.to_uhwi (), TREE_TYPE (tem));
@@ -811,7 +818,7 @@  array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
     warned = checker->check_array_ref (location, t, wi->stmt,
 				       false/*ignore_off_by_one*/);
   else if (TREE_CODE (t) == MEM_REF)
-    warned = checker->check_mem_ref (location, t,
+    warned = checker->check_mem_ref (location, t, wi->stmt,
 				     false /*ignore_off_by_one*/);
   else if (TREE_CODE (t) == ADDR_EXPR)
     {
diff --git a/gcc/gimple-array-bounds.h b/gcc/gimple-array-bounds.h
index aa7ca8e9730..2d1d48d1e94 100644
--- a/gcc/gimple-array-bounds.h
+++ b/gcc/gimple-array-bounds.h
@@ -33,7 +33,7 @@  public:
 private:
   static tree check_array_bounds (tree *tp, int *walk_subtree, void *data);
   bool check_array_ref (location_t, tree, gimple *, bool ignore_off_by_one);
-  bool check_mem_ref (location_t, tree, bool ignore_off_by_one);
+  bool check_mem_ref (location_t, tree, gimple *, bool ignore_off_by_one);
   void check_addr_expr (location_t, tree, gimple *);
   void get_value_range (irange &r, const_tree op, gimple *);
 
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 902bb70de03..c981b49e6b6 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -57,6 +57,7 @@ 
 #include "attr-fnspec.h"
 #include "pointer-query.h"
 #include "pretty-print-markup.h"
+#include "move-history-rich-location.h"
 
 /* Return true if tree node X has an associated location.  */
 
@@ -169,17 +170,19 @@  warn_string_no_nul (location_t loc, GimpleOrTree expr, const char *fname,
   if (expr)
     {
       tree func = get_callee_fndecl (expr);
+      rich_location_with_details richloc (loc, expr);
+
       if (bndrng)
 	{
 	  if (wi::ltu_p (maxsiz, bndrng[0]))
-	    warned = warning_at (loc, opt,
+	    warned = warning_at (&richloc, opt,
 				 "%qD specified bound %s exceeds "
 				 "maximum object size %E",
 				 func, bndstr, maxobjsize);
 	  else
 	    {
 	      bool maybe = wi::to_wide (size) == bndrng[0];
-	      warned = warning_at (loc, opt,
+	      warned = warning_at (&richloc, opt,
 				   exact
 				   ? G_("%qD specified bound %s exceeds "
 					"the size %E of unterminated array")
@@ -194,7 +197,7 @@  warn_string_no_nul (location_t loc, GimpleOrTree expr, const char *fname,
 	    }
 	}
       else
-	warned = warning_at (loc, opt,
+	warned = warning_at (&richloc, opt,
 			     "%qD argument missing terminating nul",
 			     func);
     }
@@ -486,14 +489,16 @@  maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp)
       tree maxobjsize = max_object_size ();
       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
 	{
+	  rich_location_with_details richloc (loc, exp);
+
 	  bool warned = false;
 	  if (tree_int_cst_equal (bndrng[0], bndrng[1]))
-	    warned = warning_at (loc, OPT_Wstringop_overread,
+	    warned = warning_at (&richloc, OPT_Wstringop_overread,
 				 "%qD specified bound %E "
 				 "exceeds maximum object size %E",
 				 fndecl, bndrng[0], maxobjsize);
 	  else
-	    warned = warning_at (loc, OPT_Wstringop_overread,
+	    warned = warning_at (&richloc, OPT_Wstringop_overread,
 				 "%qD specified bound [%E, %E] "
 				 "exceeds maximum object size %E",
 				 fndecl, bndrng[0], bndrng[1],
@@ -641,20 +646,21 @@  maybe_warn_nonstring_arg (tree fndecl, GimpleOrTree exp)
       auto_diagnostic_group d;
       if (wi::ltu_p (asize, wibnd))
 	{
+	  rich_location_with_details richloc (loc, exp);
 	  if (bndrng[0] == bndrng[1])
-	    warned = warning_at (loc, OPT_Wstringop_overread,
+	    warned = warning_at (&richloc, OPT_Wstringop_overread,
 				 "%qD argument %i declared attribute "
 				 "%<nonstring%> is smaller than the specified "
 				 "bound %wu",
 				 fndecl, argno + 1, wibnd.to_uhwi ());
 	  else if (wi::ltu_p (asize, wi::to_offset (bndrng[0])))
-	    warned = warning_at (loc, OPT_Wstringop_overread,
+	    warned = warning_at (&richloc, OPT_Wstringop_overread,
 				 "%qD argument %i declared attribute "
 				 "%<nonstring%> is smaller than "
 				 "the specified bound [%E, %E]",
 				 fndecl, argno + 1, bndrng[0], bndrng[1]);
 	  else
-	    warned = warning_at (loc, OPT_Wstringop_overread,
+	    warned = warning_at (&richloc, OPT_Wstringop_overread,
 				 "%qD argument %i declared attribute "
 				 "%<nonstring%> may be smaller than "
 				 "the specified bound [%E, %E]",
@@ -726,16 +732,17 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
       auto_diagnostic_group d;
       if (tree_int_cst_lt (maxobjsize, bndrng[0]))
 	{
+	  rich_location_with_details richloc (loc, exp);
 	  if (bndrng[0] == bndrng[1])
 	    warned = (func
-		      ? warning_at (loc, opt,
+		      ? warning_at (&richloc, opt,
 				    (maybe
 				     ? G_("%qD specified bound %E may "
 					  "exceed maximum object size %E")
 				     : G_("%qD specified bound %E "
 					  "exceeds maximum object size %E")),
 				    func, bndrng[0], maxobjsize)
-		      : warning_at (loc, opt,
+		      : warning_at (&richloc, opt,
 				    (maybe
 				     ? G_("specified bound %E may "
 					  "exceed maximum object size %E")
@@ -744,7 +751,7 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
 				    bndrng[0], maxobjsize));
 	  else
 	    warned = (func
-		      ? warning_at (loc, opt,
+		      ? warning_at (&richloc, opt,
 				    (maybe
 				     ? G_("%qD specified bound [%E, %E] may "
 					  "exceed maximum object size %E")
@@ -752,7 +759,7 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
 					  "exceeds maximum object size %E")),
 				    func,
 				    bndrng[0], bndrng[1], maxobjsize)
-		      : warning_at (loc, opt,
+		      : warning_at (&richloc, opt,
 				    (maybe
 				     ? G_("specified bound [%E, %E] may "
 					  "exceed maximum object size %E")
@@ -763,37 +770,43 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
       else if (!size || tree_int_cst_le (bndrng[0], size))
 	return false;
       else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
-	warned = (func
-		  ? warning_at (loc, opt,
+	{
+	  rich_location_with_details richloc (loc, exp);
+	  warned = (func
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD specified bound %E may exceed "
 				      "source size %E")
 				 : G_("%qD specified bound %E exceeds "
 				      "source size %E")),
 				func, bndrng[0], size)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("specified bound %E may exceed "
 				      "source size %E")
 				 : G_("specified bound %E exceeds "
 				      "source size %E")),
 				bndrng[0], size));
+	}
       else
-	warned = (func
-		  ? warning_at (loc, opt,
+	{
+	  rich_location_with_details richloc (loc, exp);
+	  warned = (func
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD specified bound [%E, %E] may "
 				      "exceed source size %E")
 				 : G_("%qD specified bound [%E, %E] exceeds "
 				      "source size %E")),
 				func, bndrng[0], bndrng[1], size)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("specified bound [%E, %E] may exceed "
 				      "source size %E")
 				 : G_("specified bound [%E, %E] exceeds "
 				      "source size %E")),
 				bndrng[0], bndrng[1], size));
+	}
       if (warned)
 	{
 	  if (pad && pad->src.ref
@@ -807,6 +820,7 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
     }
 
   bool maybe = pad && pad->dst.phi ();
+  rich_location_with_details richloc (loc, exp);
   if (maybe)
     {
       /* Issue a "maybe" warning only if the PHI refers to objects
@@ -820,14 +834,14 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
     {
       if (bndrng[0] == bndrng[1])
 	warned = (func
-		  ? warning_at (loc, opt,
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD specified size %E may "
 				      "exceed maximum object size %E")
 				 : G_("%qD specified size %E "
 				      "exceeds maximum object size %E")),
 				func, bndrng[0], maxobjsize)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("specified size %E may exceed "
 				      "maximum object size %E")
@@ -836,14 +850,14 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
 				bndrng[0], maxobjsize));
       else
 	warned = (func
-		  ? warning_at (loc, opt,
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD specified size between %E and %E "
 				      "may exceed maximum object size %E")
 				 : G_("%qD specified size between %E and %E "
 				      "exceeds maximum object size %E")),
 				func, bndrng[0], bndrng[1], maxobjsize)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("specified size between %E and %E "
 				      "may exceed maximum object size %E")
@@ -855,14 +869,14 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
     return false;
   else if (tree_int_cst_equal (bndrng[0], bndrng[1]))
     warned = (func
-	      ? warning_at (loc, opt,
+	      ? warning_at (&richloc, opt,
 			    (maybe
 			     ? G_("%qD specified bound %E may exceed "
 				  "destination size %E")
 			     : G_("%qD specified bound %E exceeds "
 				  "destination size %E")),
 			    func, bndrng[0], size)
-	      : warning_at (loc, opt,
+	      : warning_at (&richloc, opt,
 			    (maybe
 			     ? G_("specified bound %E may exceed "
 				  "destination size %E")
@@ -871,14 +885,14 @@  maybe_warn_for_bound (opt_code opt, location_t loc, GimpleOrTree exp, tree func,
 			    bndrng[0], size));
   else
     warned = (func
-	      ? warning_at (loc, opt,
+	      ? warning_at (&richloc, opt,
 			    (maybe
 			     ? G_("%qD specified bound [%E, %E] may exceed "
 				  "destination size %E")
 			     : G_("%qD specified bound [%E, %E] exceeds "
 				  "destination size %E")),
 			    func, bndrng[0], bndrng[1], size)
-	      : warning_at (loc, opt,
+	      : warning_at (&richloc, opt,
 			    (maybe
 			     ? G_("specified bound [%E, %E] exceeds "
 				  "destination size %E")
@@ -929,11 +943,13 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 {
   bool warned = false;
 
+  rich_location_with_details richloc (loc, exp);
+
   if (write && read)
     {
       if (tree_int_cst_equal (range[0], range[1]))
 	warned = (func
-		  ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+		  ? warning_n (&richloc, opt, tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("%qD may access %E byte in a region "
 				     "of size %E")
@@ -945,7 +961,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 				 : G_ ("%qD accessing %E bytes in a region "
 				       "of size %E")),
 			       func, range[0], size)
-		  : warning_n (loc, opt, tree_to_uhwi (range[0]),
+		  : warning_n (&richloc, opt, tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("may access %E byte in a region "
 				     "of size %E")
@@ -961,14 +977,14 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	{
 	  /* Avoid printing the upper bound if it's invalid.  */
 	  warned = (func
-		    ? warning_at (loc, opt,
+		    ? warning_at (&richloc, opt,
 				  (maybe
 				   ? G_("%qD may access %E or more bytes "
 					"in a region of size %E")
 				   : G_("%qD accessing %E or more bytes "
 					"in a region of size %E")),
 				  func, range[0], size)
-		    : warning_at (loc, opt,
+		    : warning_at (&richloc, opt,
 				  (maybe
 				   ? G_("may access %E or more bytes "
 					"in a region of size %E")
@@ -978,14 +994,14 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	}
       else
 	warned = (func
-		  ? warning_at (loc, opt,
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD may access between %E and %E "
 				      "bytes in a region of size %E")
 				 : G_("%qD accessing between %E and %E "
 				      "bytes in a region of size %E")),
 				func, range[0], range[1], size)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("may access between %E and %E bytes "
 				      "in a region of size %E")
@@ -999,7 +1015,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
     {
       if (tree_int_cst_equal (range[0], range[1]))
 	warned = (func
-		  ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+		  ? warning_n (&richloc, opt, tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("%qD may write %E byte into a region "
 				     "of size %E")
@@ -1011,7 +1027,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 				: G_("%qD writing %E bytes into a region "
 				     "of size %E overflows the destination")),
 			       func, range[0], size)
-		  : warning_n (loc, opt, tree_to_uhwi (range[0]),
+		  : warning_n (&richloc, opt, tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("may write %E byte into a region "
 				     "of size %E")
@@ -1027,7 +1043,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	{
 	  /* Avoid printing the upper bound if it's invalid.  */
 	  warned = (func
-		    ? warning_at (loc, opt,
+		    ? warning_at (&richloc, opt,
 				  (maybe
 				   ? G_("%qD may write %E or more bytes "
 					"into a region of size %E")
@@ -1035,7 +1051,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 					"into a region of size %E overflows "
 					"the destination")),
 				  func, range[0], size)
-		    : warning_at (loc, opt,
+		    : warning_at (&richloc, opt,
 				  (maybe
 				   ? G_("may write %E or more bytes into "
 					"a region of size %E")
@@ -1046,7 +1062,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	}
       else
 	warned = (func
-		  ? warning_at (loc, opt,
+		  ? warning_at (&richloc, opt,
 				(maybe
 				 ? G_("%qD may write between %E and %E bytes "
 				      "into a region of size %E")
@@ -1054,7 +1070,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 				      "into a region of size %E overflows "
 				      "the destination")),
 				func, range[0], range[1], size)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("may write between %E and %E bytes "
 				      "into a region of size %E")
@@ -1069,7 +1085,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
     {
       if (tree_int_cst_equal (range[0], range[1]))
 	warned = (func
-		  ? warning_n (loc, OPT_Wstringop_overread,
+		  ? warning_n (&richloc, OPT_Wstringop_overread,
 			       tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("%qD may read %E byte from a region "
@@ -1082,7 +1098,7 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 				: G_("%qD reading %E bytes from a region "
 				     "of size %E")),
 			       func, range[0], size)
-		  : warning_n (loc, OPT_Wstringop_overread,
+		  : warning_n (&richloc, OPT_Wstringop_overread,
 			       tree_to_uhwi (range[0]),
 			       (maybe
 				? G_("may read %E byte from a region "
@@ -1099,14 +1115,14 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	{
 	  /* Avoid printing the upper bound if it's invalid.  */
 	  warned = (func
-		    ? warning_at (loc, OPT_Wstringop_overread,
+		    ? warning_at (&richloc, OPT_Wstringop_overread,
 				  (maybe
 				   ? G_("%qD may read %E or more bytes "
 					"from a region of size %E")
 				   : G_("%qD reading %E or more bytes "
 					"from a region of size %E")),
 				  func, range[0], size)
-		    : warning_at (loc, OPT_Wstringop_overread,
+		    : warning_at (&richloc, OPT_Wstringop_overread,
 				  (maybe
 				   ? G_("may read %E or more bytes "
 					"from a region of size %E")
@@ -1116,14 +1132,14 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
 	}
       else
 	warned = (func
-		  ? warning_at (loc, OPT_Wstringop_overread,
+		  ? warning_at (&richloc, OPT_Wstringop_overread,
 				(maybe
 				 ? G_("%qD may read between %E and %E bytes "
 				      "from a region of size %E")
 				 : G_("%qD reading between %E and %E bytes "
 				      "from a region of size %E")),
 				func, range[0], range[1], size)
-		  : warning_at (loc, opt,
+		  : warning_at (&richloc, opt,
 				(maybe
 				 ? G_("may read between %E and %E bytes "
 				      "from a region of size %E")
@@ -1140,12 +1156,12 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
   if (tree_int_cst_equal (range[0], range[1])
       || tree_int_cst_sign_bit (range[1]))
     warned = (func
-	      ? warning_n (loc, OPT_Wstringop_overread,
+	      ? warning_n (&richloc, OPT_Wstringop_overread,
 			   tree_to_uhwi (range[0]),
 			   "%qD expecting %E byte in a region of size %E",
 			   "%qD expecting %E bytes in a region of size %E",
 			   func, range[0], size)
-	      : warning_n (loc, OPT_Wstringop_overread,
+	      : warning_n (&richloc, OPT_Wstringop_overread,
 			   tree_to_uhwi (range[0]),
 			   "expecting %E byte in a region of size %E",
 			   "expecting %E bytes in a region of size %E",
@@ -1154,22 +1170,22 @@  warn_for_access (location_t loc, tree func, GimpleOrTree exp, int opt,
     {
       /* Avoid printing the upper bound if it's invalid.  */
       warned = (func
-		? warning_at (loc, OPT_Wstringop_overread,
+		? warning_at (&richloc, OPT_Wstringop_overread,
 			      "%qD expecting %E or more bytes in a region "
 			      "of size %E",
 			      func, range[0], size)
-		: warning_at (loc, OPT_Wstringop_overread,
+		: warning_at (&richloc, OPT_Wstringop_overread,
 			      "expecting %E or more bytes in a region "
 			      "of size %E",
 			      range[0], size));
     }
   else
     warned = (func
-	      ? warning_at (loc, OPT_Wstringop_overread,
+	      ? warning_at (&richloc, OPT_Wstringop_overread,
 			    "%qD expecting between %E and %E bytes in "
 			    "a region of size %E",
 			    func, range[0], range[1], size)
-	      : warning_at (loc, OPT_Wstringop_overread,
+	      : warning_at (&richloc, OPT_Wstringop_overread,
 			    "expecting between %E and %E bytes in "
 			    "a region of size %E",
 			    range[0], range[1], size));
@@ -1400,6 +1416,8 @@  check_access (GimpleOrTree exp, tree dstwrite,
 
 	  auto_diagnostic_group d;
 	  location_t loc = get_location (exp);
+	  rich_location_with_details richloc (loc, exp);
+
 	  bool warned = false;
 	  if (dstwrite == slen && at_least_one)
 	    {
@@ -1407,12 +1425,12 @@  check_access (GimpleOrTree exp, tree dstwrite,
 		 and a source of unknown length.  The call will write
 		 at least one byte past the end of the destination.  */
 	      warned = (func
-			? warning_at (loc, opt,
+			? warning_at (&richloc, opt,
 				      "%qD writing %E or more bytes into "
 				      "a region of size %E overflows "
 				      "the destination",
 				      func, range[0], dstsize)
-			: warning_at (loc, opt,
+			: warning_at (&richloc, opt,
 				      "writing %E or more bytes into "
 				      "a region of size %E overflows "
 				      "the destination",
@@ -2566,7 +2584,9 @@  pass_waccess::check_strncat (gcall *stmt)
       && tree_int_cst_equal (destsize, maxread))
     {
       location_t loc = get_location (stmt);
-      warning_at (loc, OPT_Wstringop_overflow_,
+      rich_location_with_details richloc (loc, stmt);
+
+      warning_at (&richloc, OPT_Wstringop_overflow_,
 		  "%qD specified bound %E equals destination size",
 		  get_callee_fndecl (stmt), maxread);
 
@@ -3447,13 +3467,14 @@  pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
 	  && tree_int_cst_sgn (sizrng[0]) < 0
 	  && tree_int_cst_sgn (sizrng[1]) < 0)
 	{
+	  rich_location_with_details richloc (loc, stmt);
 	  /* Warn about negative sizes.  */
 	  if (access.second.internal_p)
 	    {
 	      const std::string argtypestr
 		= access.second.array_as_string (ptrtype);
 
-	      if (warning_at (loc, OPT_Wstringop_overflow_,
+	      if (warning_at (&richloc, OPT_Wstringop_overflow_,
 			      "bound argument %i value %s is "
 			      "negative for a variable length array "
 			      "argument %i of type %s",
@@ -3461,7 +3482,7 @@  pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype,
 			      ptridx + 1, argtypestr.c_str ()))
 		arg_warned = OPT_Wstringop_overflow_;
 	    }
-	  else if (warning_at (loc, OPT_Wstringop_overflow_,
+	  else if (warning_at (&richloc, OPT_Wstringop_overflow_,
 			       "argument %i value %s is negative",
 			       sizidx + 1, sizstr))
 	    arg_warned = OPT_Wstringop_overflow_;
diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc
index 4bccca52f0d..1c5136f99aa 100644
--- a/gcc/gimple-ssa-warn-restrict.cc
+++ b/gcc/gimple-ssa-warn-restrict.cc
@@ -41,6 +41,7 @@ 
 #include "tree-object-size.h"
 #include "calls.h"
 #include "cfgloop.h"
+#include "move-history-rich-location.h"
 #include "intl.h"
 #include "gimple-range.h"
 
@@ -1694,6 +1695,8 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
   location_t loc = gimple_location (call);
   const offset_int maxobjsize = ref.maxobjsize;
 
+  rich_location_with_details richloc (loc, call);
+
   /* Check for excessive size first and regardless of warning options
      since the result is used to make codegen decisions.  */
   if (ref.sizrange[0] > maxobjsize)
@@ -1710,13 +1713,13 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
       if (warn_stringop_overflow)
 	{
 	  if (ref.sizrange[0] == ref.sizrange[1])
-	    warned = warning_at (loc, opt,
+	    warned = warning_at (&richloc, opt,
 				 "%qD specified bound %wu "
 				 "exceeds maximum object size %wu",
 				 func, ref.sizrange[0].to_uhwi (),
 				 maxobjsize.to_uhwi ());
 	  else
-	    warned = warning_at (loc, opt,
+	    warned = warning_at (&richloc, opt,
 				 "%qD specified bound between %wu and %wu "
 				 "exceeds maximum object size %wu",
 				 func, ref.sizrange[0].to_uhwi (),
@@ -1777,7 +1780,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 	  && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE)
 	{
 	  auto_diagnostic_group d;
-	  if (warning_at (loc, opt,
+	  if (warning_at (&richloc, opt,
 			  "%qD pointer overflow between offset %s "
 			  "and size %s accessing array %qD with type %qT",
 			  func, rangestr[0], rangestr[1], ref.base, type))
@@ -1787,13 +1790,13 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 	      warned = true;
 	    }
 	  else
-	    warned = warning_at (loc, opt,
+	    warned = warning_at (&richloc, opt,
 				 "%qD pointer overflow between offset %s "
 				 "and size %s",
 				 func, rangestr[0], rangestr[1]);
 	}
       else
-	warned = warning_at (loc, opt,
+	warned = warning_at (&richloc, opt,
 			     "%qD pointer overflow between offset %s "
 			     "and size %s",
 			     func, rangestr[0], rangestr[1]);
@@ -1809,7 +1812,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 	{
 	  auto_diagnostic_group d;
 	  if ((ref.basesize < maxobjsize
-	       && warning_at (loc, opt,
+	       && warning_at (&richloc, opt,
 			      form
 			      ? G_("%qD forming offset %s is out of "
 				   "the bounds [0, %wu] of object %qD with "
@@ -1818,7 +1821,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 				   "[0, %wu] of object %qD with type %qT"),
 			      func, rangestr[0], ref.basesize.to_uhwi (),
 			      ref.base, TREE_TYPE (ref.base)))
-	      || warning_at (loc, opt,
+	      || warning_at (&richloc, opt,
 			     form
 			     ? G_("%qD forming offset %s is out of "
 				  "the bounds of object %qD with type %qT")
@@ -1833,7 +1836,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 	    }
 	}
       else if (ref.basesize < maxobjsize)
-	warned = warning_at (loc, opt,
+	warned = warning_at (&richloc, opt,
 			     form
 			     ? G_("%qD forming offset %s is out "
 				  "of the bounds [0, %wu]")
@@ -1841,7 +1844,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 				  "of the bounds [0, %wu]"),
 			     func, rangestr[0], ref.basesize.to_uhwi ());
       else
-	warned = warning_at (loc, opt,
+	warned = warning_at (&richloc, opt,
 			     form
 			     ? G_("%qD forming offset %s is out of bounds")
 			     : G_("%qD offset %s is out of bounds"),
@@ -1855,7 +1858,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
 	type = TREE_TYPE (type);
       type = TYPE_MAIN_VARIANT (type);
 
-      if (warning_at (loc, opt,
+      if (warning_at (&richloc, opt,
 		      "%qD offset %s from the object at %qE is out "
 		      "of the bounds of %qT",
 		      func, rangestr[0], ref.base, type))
@@ -1873,7 +1876,7 @@  maybe_diag_access_bounds (gimple *call, tree func, int strict,
       tree refop = TREE_OPERAND (ref.ref, 0);
       tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref.ref));
 
-      if (warning_at (loc, opt,
+      if (warning_at (&richloc, opt,
 		      "%qD offset %s from the object at %qE is out "
 		      "of the bounds of referenced subobject %qD with "
 		      "type %qT at offset %wi",
diff --git a/gcc/move-history-rich-location.cc b/gcc/move-history-rich-location.cc
new file mode 100644
index 00000000000..120498d165e
--- /dev/null
+++ b/gcc/move-history-rich-location.cc
@@ -0,0 +1,56 @@ 
+/* A rich_location subclass that lazily populates a diagnostic_path
+   with move_history events, but only if the path is actually to be
+   used.
+
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Contributed by Qing Zhao<qing.zhao@oracle.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "function.h"
+#include "diagnostic-move-history.h"
+#include "simple-diagnostic-path.h"
+#include "move-history-rich-location.h"
+
+/* Implemenation of the method make_inner_path of the class
+   lazy_move_history_path.  */
+
+std::unique_ptr<diagnostic_path>
+lazy_move_history_path::make_inner_path () const
+{
+  auto path = std::make_unique<simple_diagnostic_path>
+		(global_dc->get_reference_printer ());
+  if (!flag_diagnostics_details)
+    return path;
+  move_history_t mv_history = m_stmt ? get_move_history (m_stmt) : NULL;
+  for (move_history_t cur_ch = mv_history; cur_ch;
+       cur_ch = cur_ch->prev_move)
+    path->add_event (cur_ch->condition, cfun->decl, 1,
+		     "when the condition is evaluated to %s",
+		     cur_ch->is_true_path ? "true" : "false");
+
+  /* Add an end of path warning event in the end of the path.  */
+  if (path->num_events () > 0)
+    path->add_event (m_location, cfun->decl, 1,
+		     "out of array bounds here");
+  return path;
+}
diff --git a/gcc/move-history-rich-location.h b/gcc/move-history-rich-location.h
new file mode 100644
index 00000000000..42b64037591
--- /dev/null
+++ b/gcc/move-history-rich-location.h
@@ -0,0 +1,65 @@ 
+/* A rich_location subclass that lazily populates a diagnostic_path
+   with move_history events, but only if the path is actually to be
+   used.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Contributed by Qing Zhao<qing.zhao@oracle.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_MOVE_HISTORY_RICH_LOCATION_H
+#define GCC_MOVE_HISTORY_RICH_LOCATION_H
+
+#include "gcc-rich-location.h"
+#include "lazy-diagnostic-path.h"
+
+class lazy_move_history_path : public lazy_diagnostic_path
+{
+public:
+  lazy_move_history_path (location_t location, gimple *stmt)
+  : m_location (location), m_stmt (stmt)
+  {
+  }
+
+  std::unique_ptr<diagnostic_path>
+  make_inner_path () const final override;
+  /* This methold will be called on demand if a diagnostic is actually
+     emitted for this rich_location.  */
+  location_t m_location;
+  gimple *m_stmt;
+};
+
+class rich_location_with_details : public gcc_rich_location
+{
+public:
+  rich_location_with_details (location_t location, gimple *stmt)
+  : gcc_rich_location (location),
+    m_lazy_move_history_path (location, stmt)
+  {
+    set_path (&m_lazy_move_history_path);
+  }
+
+  rich_location_with_details (location_t location, tree exp ATTRIBUTE_UNUSED)
+  : gcc_rich_location (location),
+    m_lazy_move_history_path (location, NULL)
+  {
+  }
+
+private:
+  lazy_move_history_path m_lazy_move_history_path;
+};
+
+#endif // GCC_MOVE_HISTORY_RICH_LOCATION_H
diff --git a/gcc/testsuite/gcc.dg/pr109071.c b/gcc/testsuite/gcc.dg/pr109071.c
new file mode 100644
index 00000000000..ea647247a01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071.c
@@ -0,0 +1,43 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.  */  
+/* { dg-options "-O2 -Wall -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+
+extern void warn(void);
+static inline void assign(int val, int *regs, int index)
+{
+  if (index >= 4)
+    warn();
+  *regs = val;
+}
+struct nums {int vals[4];};
+
+void sparx5_set (int *ptr, struct nums *sg, int index)
+{
+  int *val = &sg->vals[index]; /* { dg-warning "is above array bounds" } */
+
+  assign(0,    ptr, index);
+  assign(*val, ptr, index);
+}
+/* { dg-begin-multiline-output "" }
+   NN |   int *val = &sg->vals[index];
+      |               ~~~~~~~~^~~~~~~
+  'sparx5_set': events 1-2
+   NN |   if (index >= 4)
+      |      ^
+      |      |
+      |      (1) when the condition is evaluated to true
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+      |               ~~~~~~~~~~~~~~~
+      |                       |
+      |                       (2) out of array bounds here
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN | struct nums {int vals[4];};
+      |                  ^~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_1.c b/gcc/testsuite/gcc.dg/pr109071_1.c
new file mode 100644
index 00000000000..7a562941e0c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_1.c
@@ -0,0 +1,36 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR88771, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+typedef struct {
+  int a;
+} * b;
+
+char *c, *x;
+int f;
+
+void d() {
+  b e;
+  char a = f + 1 ?: f;
+  __builtin_strncpy(c, x, f); /* { dg-warning "exceeds maximum object size" } */
+  if (a)
+    e->a = 0;
+}
+/* { dg-begin-multiline-output "" }
+   NN |   __builtin_strncpy(c, x, f);
+      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~
+  'd': events 1-2
+   NN |   char a = f + 1 ?: f;
+      |        ^
+      |        |
+      |        (1) when the condition is evaluated to false
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |   __builtin_strncpy(c, x, f);
+      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~
+      |   |
+      |   (2) out of array bounds here
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_2.c b/gcc/testsuite/gcc.dg/pr109071_2.c
new file mode 100644
index 00000000000..9cbac28a727
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_2.c
@@ -0,0 +1,50 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR85788, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -Warray-bounds -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+int b=10;
+int *d = &b, *e;
+void a(void *k, long l) {
+  long f = __builtin_object_size(k, 0);
+  __builtin___memset_chk(k, b, l, f); /* { dg-warning "is out of the bounds" } */
+}
+typedef struct {
+  int g;
+  int h;
+  char i[8000 * 8];
+} j;
+static void make_str_raster(j *k) {
+  int *c = d;
+  for (; c; c = e)
+    k->g = k->h = 32767;
+
+  a(k->i, k->g / 8 * k->h);
+  for (; d;)
+    ;
+}
+j m;
+void n() { make_str_raster(&m); }
+/* { dg-begin-multiline-output "" }
+   NN |   __builtin___memset_chk(k, b, l, f);
+      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  'n': events 1-2
+   NN |   __builtin___memset_chk(k, b, l, f);
+      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      |   |
+      |   (2) out of array bounds here
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |   for (; c; c = e)
+      |          ^
+      |          |
+      |          (1) when the condition is evaluated to true
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN | j m;
+      |   ^
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_3.c b/gcc/testsuite/gcc.dg/pr109071_3.c
new file mode 100644
index 00000000000..0461bbf5f92
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_3.c
@@ -0,0 +1,42 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR108770, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -Warray-bounds -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+extern void put(int i);
+int check_idx(int i) {
+  if (i > 1)
+    put(i);
+  return i;
+}
+const char *arr[] = {"A", 0};
+void init() {
+  int i = 0;
+  while (arr[check_idx(i)] != 0) { /* { dg-warning "is above array bounds of" } */
+    if (arr[check_idx(i)]) {}
+    i++;
+  }
+}
+/* { dg-begin-multiline-output "" }
+   NN |   while (arr[check_idx(i)] != 0) {
+      |          ~~~^~~~~~~~~~~~~~
+  'init': events 1-2
+   NN |   if (i > 1)
+      |      ^
+      |      |
+      |      (1) when the condition is evaluated to true
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |   while (arr[check_idx(i)] != 0) {
+      |          ~~~~~~~~~~~~~~~~~
+      |             |
+      |             (2) out of array bounds here
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN | const char *arr[] = {"A", 0};
+      |             ^~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_4.c b/gcc/testsuite/gcc.dg/pr109071_4.c
new file mode 100644
index 00000000000..10118104ab7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_4.c
@@ -0,0 +1,41 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR106762, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -Warray-bounds -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+typedef long unsigned int size_t;
+
+struct obj_t { size_t field0; size_t field1; };
+struct obj_array_t { size_t objcnt; struct obj_t* objary; };
+
+extern void *memset (void *__s, int __c, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__(1)));
+
+void bug(struct obj_array_t* ary)
+{
+ size_t idx = 0;
+ struct obj_t* obj;
+ if (idx < ary->objcnt)
+  obj = &ary->objary[idx];
+ else
+  obj = 0;
+ memset(&obj->field1, 0xff, sizeof(obj->field1)); /* { dg-warning "is out of the bounds" } */ 
+ obj->field0 = 0;
+}
+/* { dg-begin-multiline-output "" }
+   NN |  memset(&obj->field1, 0xff, sizeof(obj->field1));
+      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  'bug': events 1-2
+   NN |  if (idx < ary->objcnt)
+      |     ^
+      |     |
+      |     (1) when the condition is evaluated to false
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |  memset(&obj->field1, 0xff, sizeof(obj->field1));
+      |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      |  |
+      |  (2) out of array bounds here
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_5.c b/gcc/testsuite/gcc.dg/pr109071_5.c
new file mode 100644
index 00000000000..fc1a8a31c5a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_5.c
@@ -0,0 +1,33 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR115274, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -Wstringop-overread -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+#include <string.h>
+char *c;
+void a();
+int b(char *d) { return strlen(d); } /* { dg-warning "or more bytes from a region of size 0" } */
+void e() {
+  long f = 1;
+  f = b(c + f);
+  if (c == 0)
+    a(f);
+}
+/* { dg-begin-multiline-output "" }
+   NN | int b(char *d) { return strlen(d); }
+      |                         ^~~~~~~~~
+  'e': events 1-2
+   NN | int b(char *d) { return strlen(d); }
+      |                         ~~~~~~~~~
+      |                         |
+      |                         (2) out of array bounds here
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |   if (c == 0)
+      |      ^
+      |      |
+      |      (1) when the condition is evaluated to true
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/pr109071_6.c b/gcc/testsuite/gcc.dg/pr109071_6.c
new file mode 100644
index 00000000000..6d0565bda3e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109071_6.c
@@ -0,0 +1,49 @@ 
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+   due to code duplication from jump threading.
+   test case is from PR117179, which is a duplication of PR109071.  */  
+/* { dg-options "-O2 -Warray-bounds -fdiagnostics-details" } */
+/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-enable-nn-line-numbers "" } */
+const char* commands[] = {"a", "b"};
+
+int setval_internal(int comind)
+{
+  if (comind > sizeof(commands)/sizeof(commands[0])) {
+    return 0;
+  }
+
+  return 1;
+}
+
+_Bool setval_internal_tilde(int comind, const char *com,
+			    const char *val)
+{
+  int ret = setval_internal(comind);
+  if (commands[comind] == "b" && /* { dg-warning "is outside array bounds of" } */
+
+      ret)
+    return 1;
+  return 0;
+}
+/* { dg-begin-multiline-output "" }
+   NN |   if (commands[comind] == "b" &&
+      |       ~~~~~~~~^~~~~~~~
+  'setval_internal_tilde': events 1-2
+   NN |   if (comind > sizeof(commands)/sizeof(commands[0])) {
+      |      ^
+      |      |
+      |      (1) when the condition is evaluated to true
+......
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN |   if (commands[comind] == "b" &&
+      |       ~~~~~~~~~~~~~~~~
+      |               |
+      |               (2) out of array bounds here
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+   NN | const char* commands[] = {"a", "b"};
+      |             ^~~~~~~~
+   { dg-end-multiline-output "" } */