On Wed, Jul 30, 2025 at 4:42 PM Qing Zhao <qing.z...@oracle.com> wrote: > > Hi, > > This is the 8th 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. > > Compared to the 7th version of the patch: > https://gcc.gnu.org/pipermail/gcc-patches/2025-July/690407.html > > there are two major changes: > > 1. Sam reported two hangs when he tested the v7 with glibc and tinc. > fixed this issue. > 2. David provided the patch for his latest change r16-2520-g6d9152659f4f6a > included in the 8th version. > > 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 event 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 | 189 ++++++++++++++++++++++++ > 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, 1054 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 d7d5cbe7277..f57806163c3 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1622,6 +1622,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 70659fabebd..cf015a6e243 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..313266d2dc9 > --- /dev/null > +++ b/gcc/diagnostic-context-rich-location.cc > @@ -0,0 +1,189 @@ > +/* 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<diagnostics::paths::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;
can you put // BBn after the a[i] and the conditions so it's easier to connect the sources to the graph below? > + } > + 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. > + FIXME: We currently only handle GIMPLE_COND, might extend to > GIMPLE_SWITCH > + later. */ > + > + basic_block cur_bb = gimple_bb (m_stmt); > + if (!cur_bb) > + return path; > + basic_block prev_cond_bb = NULL; > + int depth = 0; > + bool should_terminate = false; > + > + 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) this condition is always true > + && (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)) > + cond_stmt = gsi_stmt (gsi); > + > + /* If there is no conditional statement in the prev_cond_bb and > + the prev_cond_bb has no single predecessor to backtrace, stop > + completely. */ why's this? > + if (!cond_stmt && !single_pred_p (prev_cond_bb)) > + { > + should_terminate = true; > + break; > + } > + /* if there is no location information for the cond_stmt, we should not > + add this event to confuse end user. */ > + else if (cond_stmt && gimple_location (cond_stmt) != UNKNOWN_LOCATION) LOCATION_LOCUS (gimple_location (cond_stmt)) != UNKNOWN_LOCATION > + { > + 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; Using BRANCH_EDGE does only work in cfgrtl, you should instead do is_branch_taken = e->flags & EDGE_TRUE_VALUE > + 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; Why do we only continue for single preds here? We should iterate to the immediate dominator. So the overall CFG walk should be like do { cond_bb = get_immediate_dominator (CDI_DOMINATORS, cur_bb); if (single_pred_p (curr_bb)) { auto gsi = gsi_last_bb (cond_bb); if (!gsi_end_p (gsi) && stmt_ends_bb_p (gsi_stmt (gsi))) { ... handle control stmt at the end on cond_bb ... } } curr_bb = cond_bb; } while (depth < flag_diagnostics_show_context && curr_bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)); stmt_ends_bb_p is is_ctrl_stmt () || is_ctrl_altering_stmt where the former includes GIMPLE_COND (and switch and more) and the latter includes for example a call that internally throws. Whether we terminate the walk upon unhandled control stmts would be up to debate, I'd skip for now, as you do and as you also skip GIMPLE_COND without location. > + } > + while (prev_cond_bb && depth < flag_diagnostics_show_context); > + if (should_terminate) > + break; > + } > + 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..676b9d23b05 > --- /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 "diagnostics/lazy-paths.h" > +#include "tree-logical-location.h" > + > +class lazy_diagnostic_context_path : public diagnostics::paths::lazy_path > +{ > +public: > + lazy_diagnostic_context_path (const tree_logical_location_manager > + &logical_loc_mgr, > + location_t location, gimple *stmt) > + : diagnostics::paths::lazy_path (logical_loc_mgr), > + m_logical_loc_mgr (logical_loc_mgr), > + m_location (location), m_stmt (stmt) > + { > + } > + > + std::unique_ptr<diagnostics::paths::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 e442a9cb73e..9deb2ec37c0 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. > + Can we have a -fdiagnostic-show-context alias that uses a sensible default for 'depth' (say, 1)? > @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); > + At which point do we perform the CFG walk to identify the control chain? My original idea was that we can stuff almost arbitrary compile-time into improving diagnostic output when we know we are going to emit it? But I suppose this now happens unconditionally, before we know we are going to warn? Maybe not in this instance, but as a general issue. Or does the computation happen lazily when the rich location is "evaluated"? > 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); please do not free dominators when they were available previously. So, set a flag above when you calculated them and only release if you did (it is IMO a good idea to not make such state dependent on warning flags). > + > 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 >