[PATCH v3 1/2][RFC] Provide more contexts for -Warray-bounds, -Wstringop-* warning messages due to code movements from compiler transformation [PR109071]
Sam James
sam@gentoo.org
Wed Oct 30 17:48:34 GMT 2024
Qing Zhao <qing.zhao@oracle.com> writes:
> Control this with a new option -fdiagnostics-details.
>
> $ 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.
>
> In order to achieve this, we add a new data structure "move_history" to record
> 1. the "condition" that triggers the code movement;
> 2. whether the code movement is on the true path of the "condition";
> 3. the "compiler transformation" that triggers the code movement.
>
> Whenever there is a code movement along control flow graph due to some
> specific transformations, such as jump threading, path isolation, tree
> sinking, etc., a move_history structure is created and attached to the
> moved gimple statement.
>
> During array out-of-bound checking or -Wstringop-* warning checking, the
> "move_history" that was attached to the gimple statement is used to form
> a sequence of diagnostic events that are added to the corresponding rich
> location to be used to report the warning message.
>
> This behavior is controled by the new option -fdiagnostics-details
> which is off by default.
>
> With this change, by adding -fdiagnostics-details,
> the warning message for the above testing case is now:
>
> $ gcc -Wall -O2 -fdiagnostics-details -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) out of array bounds here
> t.c:8:18: note: while referencing ‘vals’
> 8 | struct nums {int vals[4];};
> | ^~~~
>
> PR tree-optimization/109071
>
> gcc/ChangeLog:
>
> * Makefile.in (OBJS): Add diagnostic-move-history.o
> and move-history-diagnostic-path.o.
> * gcc/common.opt (fdiagnostics-details): New option.
> * gcc/doc/invoke.texi (fdiagnostics-details): Add
> documentation for the new option.
> * gimple-array-bounds.cc (build_rich_location_with_diagnostic_path):
> New function.
> (check_out_of_bounds_and_warn): Add one new parameter. Use rich
> location with move_history_diagnostic_path for warning_at.
> (array_bounds_checker::check_array_ref): Use rich location with
> move_history_diagnostic_path for warning_at.
> (array_bounds_checker::check_mem_ref): Add one new parameter.
> Use rich location with move_history_diagnostic_path 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-iterator.cc (gsi_remove): (gsi_remove): Remove the move
> history when removing the gimple.
> * gimple-pretty-print.cc (pp_gimple_stmt_1): Emit MV_H marking
> if the gimple has a move_history.
> * gimple-ssa-isolate-paths.cc (isolate_path): Set move history
> for the gimples of the duplicated blocks.
> * gimple-ssa-warn-restrict.cc (maybe_diag_access_bounds): Use
> rich location with move_history_diagnostic_path for warning_at.
> * gimple-ssa-warn-access.cc (warn_string_no_nul): Likewise.
> (maybe_warn_nonstring_arg): Likewise.
> (maybe_warn_for_bound): Likewise.
> (warn_for_access): Likewise.
> (check_access): Likewise.
> (pass_waccess::check_strncat): Likewise.
> (pass_waccess::maybe_check_access_sizes): Likewise.
> * tree-ssa-sink.cc (sink_code_in_bb): Create move_history for
> stmt when it is sinked.
> * toplev.cc (toplev::finalize): Call move_history_finalize.
> * tree-ssa-threadupdate.cc (ssa_redirect_edges): Create move_history
> for stmts when they are duplicated.
> (back_jt_path_registry::duplicate_thread_path): Likewise.
> * move-history-diagnostic-path.cc: New file.
> * move-history-diagnostic-path.h: New file.
> * diagnostic-move-history.cc: New file.
> * diagnostic-move-history.h: New file.
>
> gcc/testsuite/ChangeLog:
>
> PR tree-optimization/109071
>
> * gcc.dg/pr109071.c: New test.
> * gcc.dg/pr109071_1.c: New test.
> * gcc.dg/pr109071_2.c: New test.
> * gcc.dg/pr109071_3.c: New test.
> * gcc.dg/pr109071_4.c: New test.
> * gcc.dg/pr109071_5.c: New test.
> * gcc.dg/pr109071_6.c: New test.
> ---
> gcc/Makefile.in | 2 +
> gcc/common.opt | 4 +
> gcc/diagnostic-move-history.cc | 264 ++++++++++++++++++++++++++++
> gcc/diagnostic-move-history.h | 92 ++++++++++
> gcc/doc/invoke.texi | 7 +
> gcc/gimple-array-bounds.cc | 75 ++++++--
> gcc/gimple-array-bounds.h | 2 +-
> gcc/gimple-iterator.cc | 3 +
> gcc/gimple-pretty-print.cc | 4 +
> gcc/gimple-ssa-isolate-paths.cc | 11 ++
> gcc/gimple-ssa-warn-access.cc | 153 ++++++++++------
> gcc/gimple-ssa-warn-restrict.cc | 27 +--
> gcc/move-history-diagnostic-path.cc | 119 +++++++++++++
> gcc/move-history-diagnostic-path.h | 96 ++++++++++
> gcc/testsuite/gcc.dg/pr109071.c | 43 +++++
> gcc/testsuite/gcc.dg/pr109071_1.c | 36 ++++
> gcc/testsuite/gcc.dg/pr109071_2.c | 50 ++++++
> gcc/testsuite/gcc.dg/pr109071_3.c | 42 +++++
> gcc/testsuite/gcc.dg/pr109071_4.c | 41 +++++
> gcc/testsuite/gcc.dg/pr109071_5.c | 33 ++++
> gcc/testsuite/gcc.dg/pr109071_6.c | 49 ++++++
> gcc/toplev.cc | 3 +
> gcc/tree-ssa-sink.cc | 10 ++
> gcc/tree-ssa-threadupdate.cc | 25 +++
> 24 files changed, 1105 insertions(+), 86 deletions(-)
> create mode 100644 gcc/diagnostic-move-history.cc
> create mode 100644 gcc/diagnostic-move-history.h
> create mode 100644 gcc/move-history-diagnostic-path.cc
> create mode 100644 gcc/move-history-diagnostic-path.h
> create mode 100644 gcc/testsuite/gcc.dg/pr109071.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_1.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_2.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_3.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_4.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_5.c
> create mode 100644 gcc/testsuite/gcc.dg/pr109071_6.c
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 059cf2e8f79f..0d119ba46e1b 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1432,6 +1432,8 @@ OBJS = \
> df-problems.o \
> df-scan.o \
> dfp.o \
> + diagnostic-move-history.o \
> + move-history-diagnostic-path.o \
> digraph.o \
> dojump.o \
> dominance.o \
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 12b25ff486de..84ebef080143 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1566,6 +1566,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-details
> +Common Var(flag_diagnostics_details)
> +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-move-history.cc b/gcc/diagnostic-move-history.cc
> new file mode 100644
> index 000000000000..b0e8308dbf6b
> --- /dev/null
> +++ b/gcc/diagnostic-move-history.cc
> @@ -0,0 +1,264 @@
> +/* Functions to handle move history.
> + Copyright (C) 2024-2024 Free Software Foundation, Inc.
Just '2024'.
> + Contributed by Qing Zhao <qing.zhao@oracle.com>
> +
> [...]
> diff --git a/gcc/diagnostic-move-history.h b/gcc/diagnostic-move-history.h
> new file mode 100644
> index 000000000000..cac9cb1e2675
> --- /dev/null
> +++ b/gcc/diagnostic-move-history.h
> @@ -0,0 +1,92 @@
> +/* Move history associated with a gimple statement to record its history
> + of movement due to different transformations.
> + The move history will be used to construct events for later diagnostic.
> +
> + Copyright (C) 2024-2024 Free Software Foundation, Inc.
> + Contributed by Qing Zhao <qing.zhao@oracle.com>
> +
> + This file is part of GCC.
> +
> + GCC is free software; you can redistribute it and/or modify it under
> + the terms of the GNU General Public License as published by the Free
> + Software Foundation; either version 3, or (at your option) any later
> + version.
> +
> + GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> + WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
> + for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with GCC; see the file COPYING3. If not see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef DIAGNOSTIC_MOVE_HISTORY_H_INCLUDED
> +#define DIAGNOSTIC_MOVE_HISTORY_H_INCLUDED
I think usually the guards lack _INCLUDED.
> +
> +#include "hash-map.h"
> +#include "line-map.h"
> +
> +/* An enum for the reason why this move is made. Right now, there are
> + three reasons, we can add more if needed. */
> +enum move_reason {
> + COPY_BY_THREAD_JUMP,
> + COPY_BY_ISOLATE_PATH,
> + MOVE_BY_SINK,
> + COPY_BY_MAX
> +};
> +
> +/* This data structure records the information when a statement is
> + moved along control flow graph during different transformations.
> + Such information will be used by the later diagnostic messages
> + to report more contexts of the warnings or errors. */
> +struct move_history {
> + /* The location of the condition statement that triggered the code
> + movement. */
> + location_t condition;
> +
> + /* Whether this move is on the TRUE path of the condition. */
> + bool is_true_path;
> +
> + /* The reason for the code movement. */
> + enum move_reason reason;
> +
> + /* This statement itself might be a previous code movement. */
> + struct move_history *prev_move;
> +};
> +
> +typedef struct move_history *move_history_t;
> +
> +/* Create a new move history. */
> +extern move_history_t create_move_history (location_t, bool,
> + enum move_reason, move_history_t);
> +
> +typedef hash_map<const gimple *, move_history_t> move_history_map_t;
> +
> +/* Get the move history for the gimple STMT, return NULL when there is
> + no associated move history. */
> +extern move_history_t get_move_history (const gimple *);
> +
> +/* Remove the move history for STMT from the move_history_map. */
> +extern void remove_move_history (gimple *);
> +
> +/* Set move history for the gimple STMT. */
> +extern bool set_move_history (gimple *, location_t,
> + bool, enum move_reason);
> +
> +/* Reset all state for diagnostic-move-history.cc so that we can rerun the
> + compiler within the same process. For use by toplev::finalize. */
> +extern void move_history_finalize (void);
> +
> +/* Set move history to the stmt based on the edge ENTRY and whether this stmt
> + will be in the destination of the ENTRY. */
> +extern bool set_move_history_to_stmt (gimple *, edge,
> + bool, enum move_reason);
> +
> +/* Set move history to all the stmts in the basic block based on
> + the entry edge and whether this basic block will be the destination
> + of the entry edge. */
> +extern bool set_move_history_to_stmts_in_bb (basic_block, edge,
> + bool, enum move_reason);
> +
> +#endif // DIAGNOSTIC_MOVE_HISTORY_H_INCLUDED
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 987b63601520..8bb7568d0e30 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -324,6 +324,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-details
>
> @item Warning Options
> @xref{Warning Options,,Options to Request or Suppress Warnings}.
> @@ -5609,6 +5610,12 @@ 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-details
> +@item -fdiagnostics-details
> +With this option, the compiler collects more context information for
> +diagnostics and emits them to the users to provide more hints on how
> +the diagnostics come from.
> +
Two comments:
1) I don't know if we should note here that it might be a bit slower as it
requires that collection or if it's implied/obvious?
2) Should we mention a list of warnings we know are wired up to it?
(either here, or in the docs for the warnings themselves)
> @opindex fdiagnostics-parseable-fixits
> @item -fdiagnostics-parseable-fixits
> Emit fix-it hints in a machine-parseable format, suitable for consumption
> [...]
thanks,
sam
More information about the Gcc-patches
mailing list