mcf.o \
mode-switching.o \
modulo-sched.o \
+ diagnostic-context-rich-location.o \
multiple_target.o \
omp-offload.o \
omp-expand.o \
Common Var(flag_diagnostics_show_nesting_levels) Init(0)
Show nesting levels as numbers when showing nested diagnostics.
+fdiagnostics-show-context
+Common Alias(fdiagnostics-show-context=,1,0)
+
+fdiagnostics-show-context=
+Common Joined RejectNegative 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.
--- /dev/null
+/* 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.zhao@oracle.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "cfganal.h"
+#include "tree-cfg.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) // B2
+ {
+ if (is_day) // B3
+ __builtin_printf ("day"); // B4
+ else
+ __builtin_printf ("night"); // B5
+
+ if (i == -1) // B6
+ {
+ if (is_dollar) // B7
+ __builtin_printf ("dollar");// B8
+ else
+ __builtin_printf ("euro"); // B9
+ a[i] = -1; // B10 (warning here)
+ }
+ else
+ a[i] = i; // B11
+ }
+ else
+ a[i] = i + 1; // B12
+
+ 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, the interesting conditions for
+ the diagnostic are:
+ depth=1: the condition stmt at B6, the edge from B6->B7;
+ depth=2: the condition stmt at B2, the edge from B2->B3;
+
+ In order to get the interesting conditions, the key to the heuristic
+ is to backtrace the immediate dominator block chain of the current
+ block B10, such as, B7, then B6, B3, B2.
+
+ In this basic block dominator chain, identify the single predecessor
+ edges, such as B6->B7, and B2->B3.
+
+ For each of the single predecessor edge, the interesting condition is
+ embedded in the single predecessor block, and the TRUE/FALSE of this
+ condition is embedded in the edge.
+
+ 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 cond_bb = NULL;
+ int depth = 0;
+ do
+ {
+ /* Step 1. locate the immediate dominator of cur_bb. */
+ if (dom_info_available_p (cfun, CDI_DOMINATORS))
+ cond_bb = get_immediate_dominator (CDI_DOMINATORS, cur_bb);
+
+ if (!cond_bb)
+ return path;
+
+ /* Step 2. identify the single predecessor edge to locate the
+ conditional statement. */
+ if (single_pred_p (cur_bb))
+ {
+ gcc_assert (cond_bb == single_pred (cur_bb));
+ gimple *cond_stmt = NULL;
+ gimple_stmt_iterator gsi = gsi_last_bb (cond_bb);
+
+ /* Currently, we only hanlde GIMPLE_COND.
+ FIXME, will handle GIMPLE_SWITCH and other ctrl stmt later. */
+ if (gsi_stmt (gsi) && stmt_ends_bb_p (gsi_stmt (gsi)))
+ if (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)
+ cond_stmt = gsi_stmt (gsi);
+
+ /* If there is no conditional statement in the cond_bb, continue. */
+ if (!cond_stmt)
+ {
+ cur_bb = cond_bb;
+ continue;
+ }
+
+ depth++;
+
+ /* if there is no location information for the cond_stmt, we should
+ not add this event to confuse end user. */
+ if (cond_stmt
+ && LOCATION_LOCUS (gimple_location (cond_stmt))
+ != UNKNOWN_LOCATION)
+ {
+ /* Get the edge from the cond_bb to cur_bb, to determine whether
+ the stmt is on the taken path of the conditional statement. */
+ edge e = find_edge (cond_bb, cur_bb);
+ bool 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 = cond_bb;
+ }
+ while (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;
+}
--- /dev/null
+/* 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.zhao@oracle.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_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
-fdiagnostics-column-unit=@r{[}display@r{|}byte@r{]}
-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-text-art-charset=@r{[}none@r{|}ascii@r{|}unicode@r{|}emoji@r{]}
+-fdiagnostics-show-context@r{[}=@var{depth}@r{]}}
@item Warning Options
@xref{Warning Options,,Options to Request or Suppress Warnings}.
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}]
+@itemx -fno-diagnostics-show-context
+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.
+The forms @option{-fdiagnostics-show-context} and
+@option{-fno-diagnostics-show-context} are aliases for
+@option{-fdiagnostics-show-context=1} and
+@option{-fdiagnostics-show-context=0}, respectively.
+
@opindex fdiagnostics-parseable-fixits
@item -fdiagnostics-parseable-fixits
Emit fix-it hints in a machine-parseable format, suitable for consumption
#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"
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,
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);
}
{
*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);
{
*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);
}
{
*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);
}
}
}
- 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")
&& 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);
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_))
}
}
+ 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 (),
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);
{
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))
{
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_);
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)
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));
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));
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)
{
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 *);
#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. */
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")
}
}
else
- warned = warning_at (loc, opt,
+ warned = warning_at (&richloc, opt,
"%qD argument missing terminating nul",
func);
}
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],
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]",
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")
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")
"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")
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
}
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
{
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")
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")
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")
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")
{
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")
: 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")
{
/* 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")
}
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")
{
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")
: 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")
{
/* 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")
"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")
}
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")
"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")
{
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 "
: 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 "
{
/* 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")
}
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")
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",
{
/* 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));
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)
{
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",
&& 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);
&& 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",
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_;
#include "tree-object-size.h"
#include "calls.h"
#include "cfgloop.h"
+#include "diagnostic-context-rich-location.h"
#include "intl.h"
#include "gimple-range.h"
{
/* Create a new ranger instance and associate it with FUN. */
m_ptr_qry.rvals = enable_ranger (fun);
+ bool new_dominance_for_diagnostics = false;
+
+ if (flag_diagnostics_show_context
+ && !dom_info_available_p (fun, CDI_DOMINATORS))
+ {
+ calculate_dominance_info (CDI_DOMINATORS);
+ new_dominance_for_diagnostics = true;
+ }
basic_block bb;
FOR_EACH_BB_FN (bb, fun)
check_block (bb);
+ if (new_dominance_for_diagnostics
+ && 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.
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];
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 "
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",
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 "
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",
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",
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",
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 "
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],
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 "
}
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 "
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",
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 "
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)
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 (),
&& 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))
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]);
{
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 "
"[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")
}
}
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]")
"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"),
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))
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",
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
+
--- /dev/null
+/* 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 "" } */
+
--- /dev/null
+/* PR tree-optimization/109071 need more context for -Warray-bounds warnings
+ due to code duplication from jump threading.
+ to test the alias option -fdiagnostics-show-context. */
+/* { dg-options "-O2 -Wall -fdiagnostics-show-context" } */
+/* { 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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 "" } */
--- /dev/null
+/* 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();
+}