An update on this version:

1. Sam reported two hangs when he tested the v7 with glibc and tinc. 

    I have fixed this issue in my local area.

2. David provided the patch for his latest change  r16-2520-g6d9152659f4f6a

     I have included into my latest version.

The v8 is under testing, will submit again when everything looks good.

Thanks for all the help.

Qing

> On Jul 23, 2025, at 16:01, Qing Zhao <qing.z...@oracle.com> wrote:
> 
> Hi,
> 
> This is the 7th version of the patches for fixing PR109071.
> 
> Adding -fdiagnotics-show-context=N into GCC to provide context information
> to the end users on how the warnings come from, in order to help the user
> to locate the exact location in source code on the specific warnings
> due to compiler optimizations.
> 
> Richard reviewed the 6th version of the patches, and provided the following
> suggestions for the Middle end changes:
> 
> 1. Change the name of the option to -fdiagnostic-show-context=N.
> 2. The data structure "move_history" actually does not carry any new 
> information
>   than the available control flow graph, no need to add it.
> 3. Display the control condition for the select diagnostics when
>   -fdiagnostic-show-context=N is specified.
> 4. Add the changes from Kees on gimple-ssa-warn-restrict.cc:
> https://gcc.gnu.org/pipermail/gcc-patches/2025-May/684126.html
> 5. Add more testing cases. (Richard and Kees's):
> https://gcc.gnu.org/pipermail/gcc-patches/2025-June/686323.html
> https://gcc.gnu.org/pipermail/gcc-patches/2025-June/685852.html
> https://gcc.gnu.org/pipermail/gcc-patches/2025-June/685854.html
> All the testing cases in 6th version are kept.
> And also some more compilcated testing cases.
> 
> 6. Bootstrap GCC with the new -fdiagnostics-show-context=1 on by default 
> (Init (1)).
> fixed all the issues.
> 
> The diagnostic part of the changes keep the same as 6th version, which David
> has reviewed already.
> 
> In the new file "diagnostic-context-rich-location.cc", the routine
> "lazy_diagnostic_context_path::make_inner_path" is the one that back trace
> CFG to form the proper events for the path. that's the key for this whole
> change.
> 
> The comments for the routine should clearly describe the heuristic used to
> form the path.
> 
> bootstrapping and regression testing on both x86 and aarch64. No issues.
> 
> Okay for trunk?
> 
> thanks a lot.
> 
> Qing
> 
> ========================================
> 
> -fdiagnostics-show-context=N
> 
> With this option, the compiler might print the interesting control flow
> chain that guards the basic block of the statement which has the warning.
> N is the maximum depth of the control flow chain.
> Currently, The list of the impacted warning options includes:
> -Warray-bounds, -Wstringop-overflow, -Wstringop-overread,
> -Wstringop-truncation, and -Wrestrict.
> More warning options might be added to this list in future releases.
> 
> For example:
> 
> $ cat t.c
> 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];
> 
>  assign(0,    ptr, &index);
>  assign(*val, ptr, &index);
> }
> 
> $ gcc -Wall -O2  -c -o t.o t.c
> t.c: In function ‘sparx5_set’:
> t.c:12:23: warning: array subscript 4 is above array bounds of ‘int[4]’ 
> [-Warray-bounds=]
>   12 |   int *val = &sg->vals[index];
>      |       ~~~~~~~~^~~~~~~
> t.c:8:18: note: while referencing ‘vals’
>    8 | struct nums {int vals[4];};
>      |  ^~~~
> 
> In the above, Although the warning is correct in theory, the warning message
> itself is confusing to the end-user since there is information that cannot
> be connected to the source code directly.
> 
> It will be a nice improvement to add more information in the warning message
> to report where such index value come from.
> 
> With the new option -fdiagnostics-show-context=1, the warning message for
> the above testing case is now:
> 
> $ gcc -Wall -O2 -fdiagnostics-show-context=1 -c -o t.o t.c
> t.c: In function ‘sparx5_set’:
> t.c:12:23: warning: array subscript 4 is above array bounds of ‘int[4]’ 
> [-Warray-bounds=]
>   12 |   int *val = &sg->vals[index];
>      |       ~~~~~~~~^~~~~~~
>  ‘sparx5_set’: events 1-2
>    4 |   if (*index >= 4)
>      |      ^
>      |      |
>      |      (1) when the condition is evaluated to true
> ......
>   12 |   int *val = &sg->vals[index];
>      |       ~~~~~~~~~~~~~~~
>      |       |
>      |       (2) warning happens here
> t.c:8:18: note: while referencing ‘vals’
>    8 | struct nums {int vals[4];};
>      |  ^~~~
> 
> 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 diagnostic-context-rich-location.o.
> * common.opt (fdiagnostics-show-context=): New option.
> * diagnostic-context-rich-location.cc: New file.
> * diagnostic-context-rich-location.h: New file.
> * doc/invoke.texi (fdiagnostics-details): Add
> documentation for the new option.
> * 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-access.cc (warn_string_no_nul): Use rich location
> with details for warning_at.
> (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.
> * gimple-ssa-warn-restrict.cc (pass_wrestrict::execute): Calculate
> dominance info for diagnostics show context.
> (maybe_diag_overlap): Use rich location with details for warning_at.
> (maybe_diag_access_bounds): Use rich location with details for
> warning_at.
> 
> gcc/testsuite/ChangeLog:
> 
> * gcc.dg/pr109071.c: New test.
> * gcc.dg/pr109071_1.c: New test.
> * gcc.dg/pr109071_10.c: New test.
> * gcc.dg/pr109071_11.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.dg/pr109071_7.c: New test.
> * gcc.dg/pr109071_8.c: New test.
> * gcc.dg/pr109071_9.c: New test.
> * gcc.dg/pr117375.c: New test.
> ---
> gcc/Makefile.in                         |   1 +
> gcc/common.opt                          |   4 +
> gcc/diagnostic-context-rich-location.cc | 178 ++++++++++++++++++++++++
> gcc/diagnostic-context-rich-location.h  |  73 ++++++++++
> gcc/doc/invoke.texi                     |  12 ++
> gcc/gimple-array-bounds.cc              |  38 ++---
> gcc/gimple-array-bounds.h               |   2 +-
> gcc/gimple-ssa-warn-access.cc           | 131 +++++++++--------
> gcc/gimple-ssa-warn-restrict.cc         |  66 +++++----
> gcc/testsuite/gcc.dg/pr109071.c         |  43 ++++++
> gcc/testsuite/gcc.dg/pr109071_1.c       |  36 +++++
> gcc/testsuite/gcc.dg/pr109071_10.c      |  85 +++++++++++
> gcc/testsuite/gcc.dg/pr109071_11.c      |  89 ++++++++++++
> 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 +++++++
> gcc/testsuite/gcc.dg/pr109071_7.c       |  44 ++++++
> gcc/testsuite/gcc.dg/pr109071_8.c       |  51 +++++++
> gcc/testsuite/gcc.dg/pr109071_9.c       |  61 ++++++++
> gcc/testsuite/gcc.dg/pr117375.c         |  13 ++
> 22 files changed, 1043 insertions(+), 99 deletions(-)
> create mode 100644 gcc/diagnostic-context-rich-location.cc
> create mode 100644 gcc/diagnostic-context-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_10.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_11.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
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_7.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_8.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_9.c
> create mode 100644 gcc/testsuite/gcc.dg/pr117375.c
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 05dfa0871be..ea9263070dc 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1623,6 +1623,7 @@ OBJS = \
> mcf.o \
> mode-switching.o \
> modulo-sched.o \
> + diagnostic-context-rich-location.o \
> multiple_target.o \
> omp-offload.o \
> omp-expand.o \
> diff --git a/gcc/common.opt b/gcc/common.opt
> index d68d7d8d914..be6a5e6c27f 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1618,6 +1618,10 @@ fdiagnostics-minimum-margin-width=
> Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6)
> Set minimum width of left margin of source code when showing source.
> 
> +fdiagnostics-show-context=
> +Common Joined UInteger Var(flag_diagnostics_show_context) Init(0)
> +Collect and print more context information for diagnostics.
> +
> fdisable-
> Common Joined RejectNegative Var(common_deferred_options) Defer
> -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass.
> diff --git a/gcc/diagnostic-context-rich-location.cc 
> b/gcc/diagnostic-context-rich-location.cc
> new file mode 100644
> index 00000000000..022fc960862
> --- /dev/null
> +++ b/gcc/diagnostic-context-rich-location.cc
> @@ -0,0 +1,178 @@
> +/* A rich_location subclass that lazily populates a diagnostic_path
> +   with diagnostic context events, but only if the path is actually to be
> +   used.
> +
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   Contributed by Qing Zhao<qing.z...@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 "tree.h"
> +#include "gimple.h"
> +#include "gimple-iterator.h"
> +#include "cfganal.h"
> +#include "simple-diagnostic-path.h"
> +#include "diagnostic-context-rich-location.h"
> +
> +/* Implemenation of the method make_inner_path of the class
> +   lazy_diagnostic_context_path.  */
> +
> +std::unique_ptr<diagnostic_path>
> +lazy_diagnostic_context_path::make_inner_path () const
> +{
> +  auto path = std::make_unique<simple_diagnostic_path>
> + (m_logical_loc_mgr,
> + global_dc->get_reference_printer ());
> +  if (!flag_diagnostics_show_context)
> +    return path;
> +  if (!m_stmt)
> +    return path;
> +
> +  /* For the following more complicated code:
> +  if (i < 10)
> +    {
> +      if (is_day)
> + __builtin_printf ("day");
> +      else
> + __builtin_printf ("night");
> +
> +      if (i == -1)
> + {
> +  if (is_dollar)
> +    __builtin_printf ("dollar");
> +  else
> +    __builtin_printf ("euro");
> +  a[i] = -1;    ===> warning here.
> + }
> +      else
> + a[i] = i;
> +    }
> +  else
> +    a[i] = i + 1;
> +
> +  it has the following CFG:
> +
> +    B2
> +   / \
> +  V   \
> + B3    \
> + / \     \
> +       V   V     \
> +      B4  B5      V
> + \ /      B12
> + V
> + B6
> + / \
> +       V   V
> +      B7  B11
> +     / \
> +    V   V
> +   B8   B9
> +     \ /
> +      V
> +     B10 (warning here)
> +
> +  If the STMT that has warning is in B10, and the interesting conditions for
> +  the diagnostic is in the edges B6->B7, and B2->B3, There are two steps to
> +  locate the interesting control flow chain:
> +
> +  depth = 0;
> +  cur_bb = B10;
> +  Step1: If cur_bb does not have any single predecessor, We should locate to
> +    its immediate dominator that has a single predecessor first.
> +    (B7 when cur_bb is B10).
> +  Step2: For this immediate dominator, backtrace the CFG to its single
> +    predecessor (B6 when cur_bb is B10), locate the conditional statement in
> +    the end of the block (B6), determine whether the immediate dominator 
> block
> +    block (B7) is on the taken path of the condition.
> +    Add the conditional statement and whether the immediate dominator block 
> is
> +    on the taken path to each event of the path.
> +    depth++;
> +
> +    then set cur_bb to B6, repeat step1 till the entry block of the function
> +    or the value of depth exceed flag_diagnostics_show_context.  */
> +
> +  basic_block cur_bb = gimple_bb (m_stmt);
> +  if (!cur_bb)
> +    return path;
> +  basic_block prev_cond_bb = NULL;
> +  int depth = 0;
> +
> +  do {
> +    /* Step 1: locate the immediate dominator that has a single predecessor 
> of
> +       cur_bb.  */
> +    do {
> +      prev_cond_bb = single_pred_p (cur_bb)
> +     ? single_pred (cur_bb) : NULL;
> +      if (!prev_cond_bb && dom_info_available_p (cfun, CDI_DOMINATORS))
> + cur_bb = get_immediate_dominator (CDI_DOMINATORS, cur_bb);
> +      else
> + break;
> +    }
> +    while (!prev_cond_bb && cur_bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
> +
> +    if (!prev_cond_bb)
> +      return path;
> +
> +    /* Step 2. backtrace the single predecessor chain to locate the 
> conditional
> +       statement.  */
> +    do {
> +      /* If the prev_cond_bb ends with a conditional statement, get it.  */
> +      gimple *cond_stmt = NULL;
> +      gimple_stmt_iterator gsi = gsi_last_bb (prev_cond_bb);
> +      if (!gsi_end_p (gsi)
> +  && gsi_stmt (gsi)
> +  && (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND))
> + cond_stmt = gsi_stmt (gsi);
> +
> +      /* If there is no conditional statement in the prev_cond_bb and there
> + is no single predecessor, stop.  */
> +      if (!cond_stmt && !single_pred_p (prev_cond_bb))
> + break;
> +      else if (cond_stmt)
> + {
> +  depth++;
> +
> +  /* Get the edge from the prev_cond_bb to cur_bb, to determine whether
> +     the stmt is on the taken path of the conditional statement.  */
> +  edge e = find_edge (prev_cond_bb, cur_bb);
> +  bool is_branch_taken = BRANCH_EDGE (prev_cond_bb) == e;
> +  path->add_event (gimple_location (cond_stmt), cfun->decl, 1,
> +   "when the condition is evaluated to %s",
> +   is_branch_taken ? "true" : "false");
> + }
> +      cur_bb = prev_cond_bb;
> +      prev_cond_bb = single_pred_p (cur_bb)
> +     ? single_pred (cur_bb) : NULL;
> +    }
> +    while (prev_cond_bb && depth < flag_diagnostics_show_context);
> +  }
> +  while (prev_cond_bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
> + && depth < flag_diagnostics_show_context);
> +
> +
> +  /* 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,
> +     "warning happens here");
> +  return path;
> +}
> diff --git a/gcc/diagnostic-context-rich-location.h 
> b/gcc/diagnostic-context-rich-location.h
> new file mode 100644
> index 00000000000..075d2f7bed6
> --- /dev/null
> +++ b/gcc/diagnostic-context-rich-location.h
> @@ -0,0 +1,73 @@
> +/* A rich_location subclass that lazily populates a diagnostic_path
> +   with diagnostic context events, but only if the path is actually to be
> +   used.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   Contributed by Qing Zhao<qing.z...@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_DIAGNOSTIC_CONTEXT_RICH_LOCATION_H
> +#define GCC_DIAGNOSTIC_CONTEXT_RICH_LOCATION_H
> +
> +#include "gcc-rich-location.h"
> +#include "lazy-diagnostic-path.h"
> +#include "tree-logical-location.h"
> +
> +class lazy_diagnostic_context_path : public lazy_diagnostic_path
> +{
> +public:
> +  lazy_diagnostic_context_path (const tree_logical_location_manager
> + &logical_loc_mgr,
> + location_t location, gimple *stmt)
> +  : lazy_diagnostic_path (logical_loc_mgr),
> +    m_logical_loc_mgr (logical_loc_mgr),
> +    m_location (location), m_stmt (stmt)
> +  {
> +  }
> +
> +  std::unique_ptr<diagnostic_path>
> +  make_inner_path () const final override;
> +  /* This method will be called on demand if a diagnostic is actually
> +     emitted for this rich_location.  */
> +
> +  const tree_logical_location_manager &m_logical_loc_mgr;
> +  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_diagnostic_context_path (m_logical_loc_mgr, location, stmt)
> +  {
> +    set_path (&m_lazy_diagnostic_context_path);
> +  }
> +
> +  rich_location_with_details (location_t location, tree exp ATTRIBUTE_UNUSED)
> +  : gcc_rich_location (location),
> +    m_lazy_diagnostic_context_path (m_logical_loc_mgr, location, nullptr)
> +  {
> +  }
> +
> +private:
> +  const tree_logical_location_manager m_logical_loc_mgr;
> +  lazy_diagnostic_context_path m_lazy_diagnostic_context_path;
> +};
> +
> +#endif // GCC_DIAGNOSTIC_CONTEXT_RICH_LOCATION_H
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 09802303254..acba0569952 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -332,6 +332,7 @@ Objective-C and Objective-C++ Dialects}.
> -fdiagnostics-column-origin=@var{origin}
> -fdiagnostics-escape-format=@r{[}unicode@r{|}bytes@r{]}
> -fdiagnostics-text-art-charset=@r{[}none@r{|}ascii@r{|}unicode@r{|}emoji@r{]}}
> +-fdiagnostics-show-context=@var{depth}
> 
> @item Warning Options
> @xref{Warning Options,,Options to Request or Suppress Warnings}.
> @@ -5764,6 +5765,17 @@ left margin.
> This option controls the minimum width of the left margin printed by
> @option{-fdiagnostics-show-line-numbers}.  It defaults to 6.
> 
> +@opindex fdiagnostics-show-context
> +@item -fdiagnostics-show-context=@var{depth}
> +With this option, the compiler might print the interesting control flow
> +chain that guards the basic block of the statement which has the warning.
> +@var{depth} is the maximum depth of the control flow chain.
> +Currently, The list of the impacted warning options includes:
> +@option{-Warray-bounds}, @option{-Wstringop-overflow},
> +@option{-Wstringop-overread}, @option{-Wstringop-truncation}.
> +and @option{-Wrestrict}.
> +More warning options might be added to this list in future releases.
> +
> @opindex fdiagnostics-parseable-fixits
> @item -fdiagnostics-parseable-fixits
> Emit fix-it hints in a machine-parseable format, suitable for consumption
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index 22286cbb4cc..b62eb192b0a 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
> #include "tree-dfa.h"
> #include "fold-const.h"
> #include "diagnostic-core.h"
> +#include "diagnostic-context-rich-location.h"
> #include "intl.h"
> #include "tree-vrp.h"
> #include "alloc-pool.h"
> @@ -262,6 +263,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 +277,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 +302,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 +316,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 +325,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 +391,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 +424,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 +482,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 +581,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 +605,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 +628,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 +661,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 +697,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 +708,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 +722,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 +817,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 bdf8a3428a6..611bcdf17e3 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 0f4aff6b59b..abfb8685ce7 100644
> --- a/gcc/gimple-ssa-warn-access.cc
> +++ b/gcc/gimple-ssa-warn-access.cc
> @@ -57,6 +57,7 @@
> #include "pointer-query.h"
> #include "pretty-print-markup.h"
> #include "gcc-urlifier.h"
> +#include "diagnostic-context-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],
> @@ -645,20 +650,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]",
> @@ -730,16 +736,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")
> @@ -748,7 +755,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")
> @@ -756,7 +763,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")
> @@ -767,37 +774,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
> @@ -811,6 +824,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
> @@ -824,14 +838,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")
> @@ -840,14 +854,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")
> @@ -859,14 +873,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")
> @@ -875,14 +889,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")
> @@ -933,11 +947,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")
> @@ -949,7 +965,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")
> @@ -965,14 +981,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")
> @@ -982,14 +998,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")
> @@ -1003,7 +1019,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")
> @@ -1015,7 +1031,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")
> @@ -1031,7 +1047,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")
> @@ -1039,7 +1055,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")
> @@ -1050,7 +1066,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")
> @@ -1058,7 +1074,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")
> @@ -1073,7 +1089,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 "
> @@ -1086,7 +1102,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 "
> @@ -1103,14 +1119,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")
> @@ -1120,14 +1136,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")
> @@ -1144,12 +1160,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",
> @@ -1158,22 +1174,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));
> @@ -1404,6 +1420,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)
>    {
> @@ -1411,12 +1429,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",
> @@ -2583,7 +2601,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);
> 
> @@ -3464,13 +3484,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",
> @@ -3478,7 +3499,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 47263aa4d34..6da89e50806 100644
> --- a/gcc/gimple-ssa-warn-restrict.cc
> +++ b/gcc/gimple-ssa-warn-restrict.cc
> @@ -40,6 +40,7 @@
> #include "tree-object-size.h"
> #include "calls.h"
> #include "cfgloop.h"
> +#include "diagnostic-context-rich-location.h"
> #include "intl.h"
> #include "gimple-range.h"
> 
> @@ -107,10 +108,17 @@ pass_wrestrict::execute (function *fun)
>   /* Create a new ranger instance and associate it with FUN.  */
>   m_ptr_qry.rvals = enable_ranger (fun);
> 
> +  if (flag_diagnostics_show_context
> +      && !dom_info_available_p (fun, CDI_DOMINATORS))
> +    calculate_dominance_info (CDI_DOMINATORS);
> +
>   basic_block bb;
>   FOR_EACH_BB_FN (bb, fun)
>     check_block (bb);
> 
> +  if (dom_info_available_p (fun, CDI_DOMINATORS))
> +    free_dominance_info (fun, CDI_DOMINATORS);
> +
>   m_ptr_qry.flush_cache ();
> 
>   /* Release the ranger instance and replace it with a global ranger.
> @@ -1447,6 +1455,8 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
> 
>   tree func = gimple_call_fndecl (call);
> 
> +  rich_location_with_details richloc (loc, call);
> +
>   /* To avoid a combinatorial explosion of diagnostics format the offsets
>      or their ranges as strings and use them in the warning calls below.  */
>   char offstr[3][64];
> @@ -1492,7 +1502,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       if (sizrange[0] == sizrange[1])
> {
>  if (ovlsiz[0] == ovlsiz[1])
> -    warning_at (loc, OPT_Wrestrict,
> +    warning_at (&richloc, OPT_Wrestrict,
> sizrange[0] == 1
> ? (ovlsiz[0] == 1
>   ? G_("%qD accessing %wu byte at offsets %s "
> @@ -1509,7 +1519,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
> func, sizrange[0],
> offstr[0], offstr[1], ovlsiz[0], offstr[2]);
>  else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
> -    warning_n (loc, OPT_Wrestrict, sizrange[0],
> +    warning_n (&richloc, OPT_Wrestrict, sizrange[0],
>       "%qD accessing %wu byte at offsets %s "
>       "and %s overlaps between %wu and %wu bytes "
>       "at offset %s",
> @@ -1519,7 +1529,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       func, sizrange[0], offstr[0], offstr[1],
>       ovlsiz[0], ovlsiz[1], offstr[2]);
>  else
> -    warning_n (loc, OPT_Wrestrict, sizrange[0],
> +    warning_n (&richloc, OPT_Wrestrict, sizrange[0],
>       "%qD accessing %wu byte at offsets %s and "
>       "%s overlaps %wu or more bytes at offset %s",
>       "%qD accessing %wu bytes at offsets %s and "
> @@ -1532,7 +1542,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ())
> {
>  if (ovlsiz[0] == ovlsiz[1])
> -    warning_n (loc, OPT_Wrestrict, ovlsiz[0],
> +    warning_n (&richloc, OPT_Wrestrict, ovlsiz[0],
>       "%qD accessing between %wu and %wu bytes "
>       "at offsets %s and %s overlaps %wu byte at "
>       "offset %s",
> @@ -1542,7 +1552,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       func, sizrange[0], sizrange[1],
>       offstr[0], offstr[1], ovlsiz[0], offstr[2]);
>  else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
> -    warning_at (loc, OPT_Wrestrict,
> +    warning_at (&richloc, OPT_Wrestrict,
> "%qD accessing between %wu and %wu bytes at "
> "offsets %s and %s overlaps between %wu and %wu "
> "bytes at offset %s",
> @@ -1550,7 +1560,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
> offstr[0], offstr[1], ovlsiz[0], ovlsiz[1],
> offstr[2]);
>  else
> -    warning_at (loc, OPT_Wrestrict,
> +    warning_at (&richloc, OPT_Wrestrict,
> "%qD accessing between %wu and %wu bytes at "
> "offsets %s and %s overlaps %wu or more bytes "
> "at offset %s",
> @@ -1563,7 +1573,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
> ovlsiz[1] = maxobjsize.to_shwi ();
> 
>       if (ovlsiz[0] == ovlsiz[1])
> - warning_n (loc, OPT_Wrestrict, ovlsiz[0],
> + warning_n (&richloc, OPT_Wrestrict, ovlsiz[0],
>   "%qD accessing %wu or more bytes at offsets "
>   "%s and %s overlaps %wu byte at offset %s",
>   "%qD accessing %wu or more bytes at offsets "
> @@ -1571,14 +1581,14 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>   func, sizrange[0], offstr[0], offstr[1],
>   ovlsiz[0], offstr[2]);
>       else if (ovlsiz[1] >= 0 && ovlsiz[1] < maxobjsize.to_shwi ())
> - warning_at (loc, OPT_Wrestrict,
> + warning_at (&richloc, OPT_Wrestrict,
>    "%qD accessing %wu or more bytes at offsets %s "
>    "and %s overlaps between %wu and %wu bytes "
>    "at offset %s",
>    func, sizrange[0], offstr[0], offstr[1],
>    ovlsiz[0], ovlsiz[1], offstr[2]);
>       else
> - warning_at (loc, OPT_Wrestrict,
> + warning_at (&richloc, OPT_Wrestrict,
>    "%qD accessing %wu or more bytes at offsets %s "
>    "and %s overlaps %wu or more bytes at offset %s",
>    func, sizrange[0], offstr[0], offstr[1],
> @@ -1606,14 +1616,14 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       if (ovlsiz[1] == 1)
> {
>  if (open_range)
> -    warning_n (loc, OPT_Wrestrict, sizrange[1],
> +    warning_n (&richloc, OPT_Wrestrict, sizrange[1],
>       "%qD accessing %wu byte may overlap "
>       "%wu byte",
>       "%qD accessing %wu bytes may overlap "
>       "%wu byte",
>       func, sizrange[1], ovlsiz[1]);
>  else
> -    warning_n (loc, OPT_Wrestrict, sizrange[1],
> +    warning_n (&richloc, OPT_Wrestrict, sizrange[1],
>       "%qD accessing %wu byte at offsets %s "
>       "and %s may overlap %wu byte at offset %s",
>       "%qD accessing %wu bytes at offsets %s "
> @@ -1624,14 +1634,14 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
> }
> 
>       if (open_range)
> - warning_n (loc, OPT_Wrestrict, sizrange[1],
> + warning_n (&richloc, OPT_Wrestrict, sizrange[1],
>   "%qD accessing %wu byte may overlap "
>   "up to %wu bytes",
>   "%qD accessing %wu bytes may overlap "
>   "up to %wu bytes",
>   func, sizrange[1], ovlsiz[1]);
>       else
> - warning_n (loc, OPT_Wrestrict, sizrange[1],
> + warning_n (&richloc, OPT_Wrestrict, sizrange[1],
>   "%qD accessing %wu byte at offsets %s and "
>   "%s may overlap up to %wu bytes at offset %s",
>   "%qD accessing %wu bytes at offsets %s and "
> @@ -1644,14 +1654,14 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>   if (sizrange[1] >= 0 && sizrange[1] < maxobjsize.to_shwi ())
>     {
>       if (open_range)
> - warning_n (loc, OPT_Wrestrict, ovlsiz[1],
> + warning_n (&richloc, OPT_Wrestrict, ovlsiz[1],
>   "%qD accessing between %wu and %wu bytes "
>   "may overlap %wu byte",
>   "%qD accessing between %wu and %wu bytes "
>   "may overlap up to %wu bytes",
>   func, sizrange[0], sizrange[1], ovlsiz[1]);
>       else
> - warning_n (loc, OPT_Wrestrict, ovlsiz[1],
> + warning_n (&richloc, OPT_Wrestrict, ovlsiz[1],
>   "%qD accessing between %wu and %wu bytes "
>   "at offsets %s and %s may overlap %wu byte "
>   "at offset %s",
> @@ -1663,7 +1673,7 @@ maybe_diag_overlap (location_t loc, gimple *call, 
> builtin_access &acs)
>       return true;
>     }
> 
> -  warning_n (loc, OPT_Wrestrict, ovlsiz[1],
> +  warning_n (&richloc, OPT_Wrestrict, ovlsiz[1],
>     "%qD accessing %wu or more bytes at offsets %s "
>     "and %s may overlap %wu byte at offset %s",
>     "%qD accessing %wu or more bytes at offsets %s "
> @@ -1693,6 +1703,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)
> @@ -1709,13 +1721,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 (),
> @@ -1776,7 +1788,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))
> @@ -1786,13 +1798,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]);
> @@ -1808,7 +1820,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 "
> @@ -1817,7 +1829,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")
> @@ -1832,7 +1844,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]")
> @@ -1840,7 +1852,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"),
> @@ -1854,7 +1866,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))
> @@ -1872,7 +1884,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/testsuite/gcc.dg/pr109071.c b/gcc/testsuite/gcc.dg/pr109071.c
> new file mode 100644
> index 00000000000..74b7b46221e
> --- /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-show-context=1" } */
> +/* { 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) warning happens 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..592a9989752
> --- /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-show-context=1" } */
> +/* { 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) warning happens here
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/gcc.dg/pr109071_10.c 
> b/gcc/testsuite/gcc.dg/pr109071_10.c
> new file mode 100644
> index 00000000000..1fe7edc7ac9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr109071_10.c
> @@ -0,0 +1,85 @@
> +/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
> +   due to compiler optimization.  */
> +/* { dg-options "-O2 -Warray-bounds -fdiagnostics-show-context=3" } */
> +/* { dg-additional-options "-fdiagnostics-show-line-numbers 
> -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
> +/* { dg-enable-nn-line-numbers "" } */
> +#define MAX_LENGTH 10
> +int a[MAX_LENGTH];
> +
> +void __attribute__ ((noinline))  foo (int i, bool is_dollar)
> +{
> +  if (i < MAX_LENGTH)
> +    {
> +      if (i == -1)
> +        {
> +          if (is_dollar)
> +            __builtin_printf ("dollar");
> +          else
> +            __builtin_printf ("euro");
> +          a[i] = -1; /* { dg-warning "is below array bounds of" } */
> +        }
> +      else
> +        a[i] = i;
> +    }
> +  else
> +    a[i] = i + 1; /* { dg-warning "is above array bounds of" } */
> +}
> +
> +int main ()
> +{
> +  for (int i = 0; i < MAX_LENGTH; i++)
> +    foo (i, true);
> +  return 0;
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = i + 1;
> +      |     ~^~~
> +  'foo': events 1-2
> +   NN |   if (i < MAX_LENGTH)
> +      |      ^
> +      |      |
> +      |      (1) when the condition is evaluated to false
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = i + 1;
> +      |     ~~~~
> +      |      |
> +      |      (2) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |           a[i] = -1;
> +      |           ~^~~
> +  'foo': events 1-3
> +   NN |   if (i < MAX_LENGTH)
> +      |      ~    
> +      |      |
> +      |      (2) when the condition is evaluated to true
> +   NN |     {
> +   NN |       if (i == -1)
> +      |          ^
> +      |          |
> +      |          (1) when the condition is evaluated to true
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |           a[i] = -1;
> +      |           ~~~~
> +      |            |
> +      |            (3) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> +
> diff --git a/gcc/testsuite/gcc.dg/pr109071_11.c 
> b/gcc/testsuite/gcc.dg/pr109071_11.c
> new file mode 100644
> index 00000000000..b9973bd85da
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr109071_11.c
> @@ -0,0 +1,89 @@
> +/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
> +   due to compiler optimization.  */
> +/* { dg-options "-O2 -Warray-bounds -fdiagnostics-show-context=3" } */
> +/* { dg-additional-options "-fdiagnostics-show-line-numbers 
> -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
> +/* { dg-enable-nn-line-numbers "" } */
> +#define MAX_LENGTH 10
> +int a[MAX_LENGTH];
> +
> +void __attribute__ ((noinline))  foo (int i, bool is_day, bool is_dollar)
> +{
> +  if (i < MAX_LENGTH)
> +    {
> +      if (is_day)
> +        __builtin_printf ("day");
> +      else
> +        __builtin_printf ("night");
> +      if (i == -1)
> +        {
> +          if (is_dollar)
> +            __builtin_printf ("dollar");
> +          else
> +            __builtin_printf ("euro");
> +          a[i] = -1; /* { dg-warning "is below array bounds of" } */
> +        }
> +      else
> +        a[i] = i;
> +    }
> +  else
> +    a[i] = i + 1; /* { dg-warning "is above array bounds of" } */
> +}
> +
> +int main ()
> +{
> +  for (int i = 0; i < MAX_LENGTH; i++)
> +    foo (i, false, true);
> +  return 0;
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = i + 1;
> +      |     ~^~~
> +  'foo': events 1-2
> +   NN |   if (i < MAX_LENGTH)
> +      |      ^
> +      |      |
> +      |      (1) when the condition is evaluated to false
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = i + 1;
> +      |     ~~~~
> +      |      |
> +      |      (2) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |           a[i] = -1;
> +      |           ~^~~
> +  'foo': events 1-3
> +   NN |   if (i < MAX_LENGTH)
> +      |      ~    
> +      |      |
> +      |      (2) when the condition is evaluated to true
> +......
> +   NN |       if (i == -1)
> +      |          ^
> +      |          |
> +      |          (1) when the condition is evaluated to true
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |           a[i] = -1;
> +      |           ~~~~
> +      |            |
> +      |            (3) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { 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..549a8c4ed87
> --- /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-show-context=1" } */
> +/* { 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) warning happens here
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |   for (; c; c = e)
> +      |          ^
> +      |          |
> +      |          (1) when the condition is evaluated to false
> +   { 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..c7b86ebd060
> --- /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-show-context=1" } */
> +/* { 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) warning happens 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..308249ea674
> --- /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-show-context=1" } */
> +/* { 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) warning happens 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..466d5181dc7
> --- /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-show-context=1" } */
> +/* { 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(long);
> +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) warning happens 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..eddf15b350c
> --- /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-show-context=1" } */
> +/* { 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) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | const char* commands[] = {"a", "b"};
> +      |             ^~~~~~~~
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/gcc.dg/pr109071_7.c 
> b/gcc/testsuite/gcc.dg/pr109071_7.c
> new file mode 100644
> index 00000000000..a54a9f5dea5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr109071_7.c
> @@ -0,0 +1,44 @@
> +/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
> +   due to compiler optimization.  */
> +/* { dg-options "-O2 -Warray-bounds -fdiagnostics-show-context=1" } */
> +/* { dg-additional-options "-fdiagnostics-show-line-numbers 
> -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
> +/* { dg-enable-nn-line-numbers "" } */
> +#define MAX_LENGTH 10
> +int a[MAX_LENGTH];
> +
> +void __attribute__ ((noinline))  foo (int i)
> +{
> +  if (i == 12)
> +    a[i] = -1; /* { dg-warning "is above array bounds of" } */
> +  else
> +    a[i] = i;
> +}
> +
> +int main ()
> +{
> +  for (int i = 0; i < MAX_LENGTH; i++)
> +    foo (i);
> +  return 0;
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = -1;
> +      |     ~^~~
> +  'foo': events 1-2
> +   NN |   if (i == 12)
> +      |      ^
> +      |      |
> +      |      (1) when the condition is evaluated to true
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |     a[i] = -1;
> +      |     ~~~~
> +      |      |
> +      |      (2) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/gcc.dg/pr109071_8.c 
> b/gcc/testsuite/gcc.dg/pr109071_8.c
> new file mode 100644
> index 00000000000..13af458e1b2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr109071_8.c
> @@ -0,0 +1,51 @@
> +/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
> +   due to compiler optimization.  */
> +/* { dg-options "-O2 -Warray-bounds -fdiagnostics-show-context=1" } */
> +/* { dg-additional-options "-fdiagnostics-show-line-numbers 
> -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
> +/* { dg-enable-nn-line-numbers "" } */
> +#define MAX_LENGTH 10
> +int a[MAX_LENGTH];
> +
> +void __attribute__ ((noinline))  foo (int i, bool is_dollar)
> +{
> +  if (i == -1)
> +    {
> +      if (is_dollar)
> + __builtin_printf ("dollar");
> +      else
> + __builtin_printf ("euro");
> +      a[i] = -1; /* { dg-warning "is below array bounds of" } */
> +    }
> +  else
> +    a[i] = i;
> +}
> +
> +int main ()
> +{
> +  for (int i = 0; i < MAX_LENGTH; i++)
> +    foo (i, true);
> +  return 0;
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |       a[i] = -1;
> +      |       ~^~~
> +  'foo': events 1-2
> +   NN |   if (i == -1)
> +      |      ^
> +      |      |
> +      |      (1) when the condition is evaluated to true
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |       a[i] = -1;
> +      |       ~~~~
> +      |        |
> +      |        (2) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/gcc.dg/pr109071_9.c 
> b/gcc/testsuite/gcc.dg/pr109071_9.c
> new file mode 100644
> index 00000000000..48925717692
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr109071_9.c
> @@ -0,0 +1,61 @@
> +/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
> +   due to compiler optimization.  */
> +/* { dg-options "-O2 -Warray-bounds -fdiagnostics-show-context=1" } */
> +/* { dg-additional-options "-fdiagnostics-show-line-numbers 
> -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
> +/* { dg-enable-nn-line-numbers "" } */
> +#define MAX_LENGTH 10
> +int a[MAX_LENGTH];
> +
> +void __attribute__ ((noinline))  foo (int i, bool is_dollar,
> +      bool is_hour, bool is_color)
> +{
> +  if (i == -1)
> +    {
> +      if (is_dollar)
> + __builtin_printf ("dollar");
> +      else
> + __builtin_printf ("euro");
> +      if (is_hour)
> + __builtin_printf ("hour");
> +      else
> + {
> +  if (is_color)
> +    __builtin_printf ("color minute");
> +  else 
> +    __builtin_printf ("non minute");
> + }
> +      a[i] = -1; /* { dg-warning "is below array bounds of" } */
> +    }
> +  else
> +    a[i] = i;
> +}
> +
> +int main ()
> +{
> +  for (int i = 0; i < MAX_LENGTH; i++)
> +    foo (i, true, false, true);
> +  return 0;
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |       a[i] = -1;
> +      |       ~^~~
> +  'foo': events 1-2
> +   NN |   if (i == -1)
> +      |      ^
> +      |      |
> +      |      (1) when the condition is evaluated to true
> +......
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN |       a[i] = -1;
> +      |       ~~~~
> +      |        |
> +      |        (2) warning happens here
> +   { dg-end-multiline-output "" } */
> +
> +/* { dg-begin-multiline-output "" }
> +   NN | int a[MAX_LENGTH];
> +      |     ^
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/gcc.dg/pr117375.c b/gcc/testsuite/gcc.dg/pr117375.c
> new file mode 100644
> index 00000000000..9679a034d6d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr117375.c
> @@ -0,0 +1,13 @@
> +/* PR middle-end/117375 ICE with -fdiagnostics-show-context=1 patch in sink 
> pass.  */ 
> +/*    { dg-do compile }
> +      { dg-options "-O2 -Wall -fdiagnostics-show-context=1" } */
> +
> +int st, st_0;
> +int nbFilledBytes, max;
> +void ec_enc_shrink();
> +void max_allowed() {
> +  int nbAvailableBytes = nbFilledBytes;
> +  if (st && st_0)
> +    if (max < nbAvailableBytes)
> +      ec_enc_shrink();
> +}
> -- 
> 2.31.1
> 

Reply via email to