From: Martin Sebor <msebor@gmail.com>
To: gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] improve warning suppression for inlined functions (PR 98465, 98512)
Date: Thu, 21 Jan 2021 16:46:27 -0700 [thread overview]
Message-ID: <945093c7-de5e-0350-6030-e4e79ea41161@gmail.com> (raw)
In-Reply-To: <2e49b6c6-a403-a207-c41e-58f78df96b84@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2505 bytes --]
The initial patch I posted is missing initialization for a couple
of locals. I'd noticed it in testing but forgot to add the fix to
the patch before posting it. I have corrected that in the updated
revision and also added the test case from pr98512, and retested
the whole thing on x86_64-linux.
On 1/19/21 11:58 AM, Martin Sebor wrote:
> std::string tends to trigger a class of false positive out of bounds
> access warnings for code GCC cannot prove is unreachable because of
> missing aliasing constrains, and that ends up expanded inline into
> user code. Simply inserting the contents of a constant char array
> does that. In GCC 10 these false positives are suppressed due to
> -Wno-system-headers, but in GCC 11, to help detect calls rendered
> invalid by user code passing in either incorrect or insufficiently
> constrained arguments, -Wno-system-header no longer has this effect
> on invalid access warnings.
>
> To solve the problem without at least partially reverting the change
> and going back to the GCC 10 way of things for the affected subset
> of calls (just memcpy and memmove), the attached patch enhances
> the #pragma GCC diagnostic machinery to consider not just a single
> location for inlined code but all locations at which an expression
> and its callers are inlined all the way up the stack. This gives
> each author of a function involved in inlining the ability to
> control a warning issued for the code, not just the user into whose
> code all the calls end up inlined. To resolve PR 98465, it lets us
> suppress the false positives selectively in std::string rather
> than across the board in GCC.
>
> The solution is to provide a new pair of overloads for warning
> functions that, instead of taking a single location argument, take
> a tree node from which the location(s) are determined. The tree
> argument is indirect because the diagnostic machinery doesn't (and
> cannot without more intrusive changes) at the moment depend on
> the various tree definitions. A nice feature of these overloads
> is that they do away with the need for the %K directive (and in
> the future also %G, with another enhancement to accept a gimple*
> argument).
>
> This patch depends on the fix for PR 98664 (already approved but
> not yet checked in). I've tested it on x86_64-linux.
>
> To avoid fallout I tried to keep the changes to a minimum, and
> so the design isn't as robust as I'd like it ultimately to be.
> I plan to enhance it in stage 1.
>
> Martin
[-- Attachment #2: gcc-98465.diff --]
[-- Type: text/x-patch, Size: 54918 bytes --]
PR middle-end/98465 - Bogus -Wstringop-overread in std::string
PR middle-end/98512 - “#pragma GCC diagnostic ignored” ineffective in conjunction with alias attribute
gcc/ChangeLog:
PR middle-end/98465
PR middle-end/98512
* builtins.c (class diag_inlining_context): New class.
(maybe_warn_for_bound): Adjust signature. Use diag_inlining_context.
(warn_for_access): Same.
(check_access): Remove calls to tree_inlined_location.
(expand_builtin_strncmp): Remove argument from calls to
maybe_warn_for_bound.
(warn_dealloc_offset): Adjust signature. Use diag_inlining_context.
(maybe_emit_free_warning): Remove calls to tree_inlined_location.
* diagnostic-core.h (warning, warning_n): New overloads.
* diagnostic-metadata.h (class diagnostic_metadata::location_context):
New.
(struct diagnostic_info): Declare.
* diagnostic.c (location_context::locations): Define.
(update_effective_level_from_pragmas): Use location_context to test
inlinined locations.
(diagnostic_report_diagnostic): Set location context.
(warning, warning_n): Define new overloads.
* diagnostic.h (diagnostic_inhibit_notes):
gcc/cp/ChangeLog:
* mapper-client.cc: Include headers needed by others.
libstdc++-v3/ChangeLog:
PR middle-end/98465
* include/bits/basic_string.tcc (_M_replace): Suppress false positive
warnings.
* testsuite/18_support/new_delete_placement.cc: Suppress valid warnings.
* testsuite/20_util/monotonic_buffer_resource/allocate.cc: Same.
* testsuite/20_util/unsynchronized_pool_resource/allocate.cc: Same.
gcc/testsuite/ChangeLog:
PR middle-end/98512
* gcc.dg/pragma-diag-9.c: New test.
* gcc.dg/pragma-diag-10.c: New test.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 0aed008687c..39fe1d0a6e0 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "optabs.h"
#include "emit-rtl.h"
#include "recog.h"
-#include "diagnostic-core.h"
+#include "diagnostic.h"
#include "alias.h"
#include "fold-const.h"
#include "fold-const-call.h"
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-outof-ssa.h"
#include "attr-fnspec.h"
#include "demangle.h"
+#include "tree-pretty-print.h"
struct target_builtins default_target_builtins;
#if SWITCHABLE_TARGET
@@ -749,6 +750,93 @@ is_builtin_name (const char *name)
return false;
}
+/* Class to override the base location context for an expression EXPR. */
+
+class diag_inlining_context: public diagnostic_metadata::location_context
+{
+ public:
+ diag_inlining_context (tree expr): m_expr (expr), m_ao (), m_loc () { }
+
+ virtual void locations (vec<location_t> &locs, diagnostic_info *di)
+ {
+ set_locations (&locs, di);
+ }
+
+ virtual void set_location (diagnostic_info *);
+
+ private:
+ void set_locations (vec<location_t> *, diagnostic_info *);
+
+ /* The expression for which a diagnostic is being issued. */
+ tree m_expr;
+ /* The "abstract origin" of the diagnosed expression, or the BLOCK
+ into which the function containing the expression is inlined. */
+ tree m_ao;
+ /* The expression location. */
+ location_t m_loc;
+};
+
+/* Lazily initialize the expression abstract origin and location. */
+
+/* virtual */ void
+diag_inlining_context::set_location (diagnostic_info *di)
+{
+ if (m_ao
+ && pp_ti_abstract_origin (&di->message)
+ && m_loc != UNKNOWN_LOCATION)
+ {
+ *pp_ti_abstract_origin (&di->message) = m_ao;
+ di->message.set_location (0, m_loc, SHOW_RANGE_WITH_CARET);
+ }
+ else
+ set_locations (NULL, di);
+}
+
+/* If LOC is nonnull, fill *LOCS with the locations M_EXPR has been inlined
+ into and if DI is nonnull, set *DI's message abstract origin and location.
+ Set M_MO. */
+
+/* virtual */ void
+diag_inlining_context::set_locations (vec<location_t> *locs,
+ diagnostic_info *di)
+{
+ tree block = TREE_BLOCK (m_expr);
+
+ while (block && TREE_CODE (block) == BLOCK
+ && BLOCK_ABSTRACT_ORIGIN (block))
+ {
+ tree ao = BLOCK_ABSTRACT_ORIGIN (block);
+ if (TREE_CODE (ao) == FUNCTION_DECL)
+ {
+ if (!m_ao)
+ m_ao = block;
+
+ if (!locs)
+
+ break;
+ locs->safe_push (BLOCK_SOURCE_LOCATION (block));
+ }
+ else if (TREE_CODE (ao) != BLOCK)
+ break;
+
+ block = BLOCK_SUPERCONTEXT (block);
+ }
+
+ m_loc = EXPR_LOCATION (m_expr);
+ /* Only consider macro expansion when the block traversal failed
+ to find a location. Otherwise it's not relevant. */
+ m_loc = expansion_point_location_if_in_system_header (m_loc);
+ if (locs)
+ locs->safe_push (m_loc);
+
+ if (di)
+ {
+ if (pp_ti_abstract_origin (&di->message))
+ *pp_ti_abstract_origin (&di->message) = m_ao;
+ di->message.set_location (0, m_loc, SHOW_RANGE_WITH_CARET);
+ }
+}
+
/* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with
its "internal" name, which normally contains the prefix "__builtin". */
@@ -3931,7 +4019,7 @@ determine_block_size (tree len, rtx len_rtx,
accessing an object with SIZE. */
static bool
-maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
+maybe_warn_for_bound (int opt, tree exp, tree func,
tree bndrng[2], tree size, const access_data *pad = NULL)
{
if (!bndrng[0] || TREE_NO_WARNING (exp))
@@ -3939,6 +4027,8 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
tree maxobjsize = max_object_size ();
+ diag_inlining_context dic (exp);
+
bool warned = false;
if (opt == OPT_Wstringop_overread)
@@ -3949,72 +4039,71 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
{
if (bndrng[0] == bndrng[1])
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD specified bound %E may "
- "exceed maximum object size %E")
- : G_("%K%qD specified bound %E "
- "exceeds maximum object size %E")),
- exp, func, bndrng[0], maxobjsize)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified bound %E may "
- "exceed maximum object size %E")
- : G_("%Kspecified bound %E "
- "exceeds maximum object size %E")),
- exp, bndrng[0], maxobjsize));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("specified bound %E may "
+ "exceed maximum object size %E")
+ : G_("specified bound %E "
+ "exceeds maximum object size %E")),
+ bndrng[0], maxobjsize));
else
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD specified bound [%E, %E] may "
- "exceed maximum object size %E")
- : G_("%K%qD specified bound [%E, %E] "
- "exceeds maximum object size %E")),
- exp, func,
- bndrng[0], bndrng[1], maxobjsize)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified bound [%E, %E] may "
- "exceed maximum object size %E")
- : G_("%Kspecified bound [%E, %E] "
- "exceeds maximum object size %E")),
- exp, bndrng[0], bndrng[1], maxobjsize));
+ ? warning (dic, opt,
+ (maybe
+ ? G_("%qD specified bound [%E, %E] may "
+ "exceed maximum object size %E")
+ : G_("%qD specified bound [%E, %E] "
+ "exceeds maximum object size %E")),
+ func, bndrng[0], bndrng[1], maxobjsize)
+ : warning (dic, opt,
+ (maybe
+ ? G_("specified bound [%E, %E] may "
+ "exceed maximum object size %E")
+ : G_("specified bound [%E, %E] "
+ "exceeds maximum object size %E")),
+ bndrng[0], bndrng[1], maxobjsize));
}
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,
- (maybe
- ? G_("%K%qD specified bound %E may exceed "
- "source size %E")
- : G_("%K%qD specified bound %E exceeds "
- "source size %E")),
- exp, func, bndrng[0], size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified bound %E may exceed "
- "source size %E")
- : G_("%Kspecified bound %E exceeds "
- "source size %E")),
- exp, bndrng[0], size));
+ ? warning (dic, 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 (dic, 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,
- (maybe
- ? G_("%K%qD specified bound [%E, %E] may "
- "exceed source size %E")
- : G_("%K%qD specified bound [%E, %E] exceeds "
- "source size %E")),
- exp, func, bndrng[0], bndrng[1], size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified bound [%E, %E] may exceed "
- "source size %E")
- : G_("%Kspecified bound [%E, %E] exceeds "
- "source size %E")),
- exp, bndrng[0], bndrng[1], size));
+ ? warning (dic, 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 (dic, 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)
@@ -4037,72 +4126,71 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
{
if (bndrng[0] == bndrng[1])
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD specified size %E may "
- "exceed maximum object size %E")
- : G_("%K%qD specified size %E "
- "exceeds maximum object size %E")),
- exp, func, bndrng[0], maxobjsize)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified size %E may exceed "
- "maximum object size %E")
- : G_("%Kspecified size %E exceeds "
- "maximum object size %E")),
- exp, bndrng[0], maxobjsize));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("specified size %E may exceed "
+ "maximum object size %E")
+ : G_("specified size %E exceeds "
+ "maximum object size %E")),
+ bndrng[0], maxobjsize));
else
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD specified size between %E and %E "
- "may exceed maximum object size %E")
- : G_("%K%qD specified size between %E and %E "
- "exceeds maximum object size %E")),
- exp, func,
- bndrng[0], bndrng[1], maxobjsize)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kspecified size between %E and %E "
- "may exceed maximum object size %E")
- : G_("%Kspecified size between %E and %E "
- "exceeds maximum object size %E")),
- exp, bndrng[0], bndrng[1], maxobjsize));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("specified size between %E and %E "
+ "may exceed maximum object size %E")
+ : G_("specified size between %E and %E "
+ "exceeds maximum object size %E")),
+ bndrng[0], bndrng[1], maxobjsize));
}
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_Wstringop_overflow_,
- (maybe
- ? G_("%K%qD specified bound %E may exceed "
- "destination size %E")
- : G_("%K%qD specified bound %E exceeds "
- "destination size %E")),
- exp, func, bndrng[0], size)
- : warning_at (loc, OPT_Wstringop_overflow_,
- (maybe
- ? G_("%Kspecified bound %E may exceed "
- "destination size %E")
- : G_("%Kspecified bound %E exceeds "
- "destination size %E")),
- exp, bndrng[0], size));
+ ? warning (dic, OPT_Wstringop_overflow_,
+ (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 (dic, OPT_Wstringop_overflow_,
+ (maybe
+ ? G_("specified bound %E may exceed "
+ "destination size %E")
+ : G_("specified bound %E exceeds "
+ "destination size %E")),
+ bndrng[0], size));
else
warned = (func
- ? warning_at (loc, OPT_Wstringop_overflow_,
- (maybe
- ? G_("%K%qD specified bound [%E, %E] may exceed "
- "destination size %E")
- : G_("%K%qD specified bound [%E, %E] exceeds "
- "destination size %E")),
- exp, func, bndrng[0], bndrng[1], size)
- : warning_at (loc, OPT_Wstringop_overflow_,
- (maybe
- ? G_("%Kspecified bound [%E, %E] exceeds "
- "destination size %E")
- : G_("%Kspecified bound [%E, %E] exceeds "
- "destination size %E")),
- exp, bndrng[0], bndrng[1], size));
+ ? warning (dic, OPT_Wstringop_overflow_,
+ (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 (dic, OPT_Wstringop_overflow_,
+ (maybe
+ ? G_("specified bound [%E, %E] exceeds "
+ "destination size %E")
+ : G_("specified bound [%E, %E] exceeds "
+ "destination size %E")),
+ bndrng[0], bndrng[1], size));
if (warned)
{
@@ -4129,76 +4217,76 @@ maybe_warn_for_bound (int opt, location_t loc, tree exp, tree func,
Returns true when a warning has been issued. */
static bool
-warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
+warn_for_access (tree func, tree exp, int opt, tree range[2],
tree size, bool write, bool read, bool maybe)
{
+ diag_inlining_context dic (exp);
+
bool warned = false;
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 (dic, opt, tree_to_uhwi (range[0]),
(maybe
- ? G_("%K%qD may access %E byte in a region "
+ ? G_("%qD may access %E byte in a region "
"of size %E")
- : G_("%K%qD accessing %E byte in a region "
+ : G_("%qD accessing %E byte in a region "
"of size %E")),
- (maybe
- ? G_ ("%K%qD may access %E bytes in a region "
- "of size %E")
- : G_ ("%K%qD accessing %E bytes in a region "
- "of size %E")),
- exp, func, range[0], size)
- : warning_n (loc, opt, tree_to_uhwi (range[0]),
(maybe
- ? G_("%Kmay access %E byte in a region "
+ ? G_ ("%qD may access %E bytes in a region "
+ "of size %E")
+ : G_ ("%qD accessing %E bytes in a region "
+ "of size %E")),
+ func, range[0], size)
+ : warning_n (dic, opt, tree_to_uhwi (range[0]),
+ (maybe
+ ? G_("may access %E byte in a region "
"of size %E")
- : G_("%Kaccessing %E byte in a region "
+ : G_("accessing %E byte in a region "
"of size %E")),
(maybe
- ? G_("%Kmay access %E bytes in a region "
+ ? G_("may access %E bytes in a region "
"of size %E")
- : G_("%Kaccessing %E bytes in a region "
+ : G_("accessing %E bytes in a region "
"of size %E")),
- exp, range[0], size));
+ range[0], size));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD may access %E or more bytes "
- "in a region of size %E")
- : G_("%K%qD accessing %E or more bytes "
- "in a region of size %E")),
- exp, func, range[0], size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kmay access %E or more bytes "
- "in a region of size %E")
- : G_("%Kaccessing %E or more bytes "
- "in a region of size %E")),
- exp, range[0], size));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("may access %E or more bytes "
+ "in a region of size %E")
+ : G_("accessing %E or more bytes "
+ "in a region of size %E")),
+ range[0], size));
}
else
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD may access between %E and %E "
- "bytes in a region of size %E")
- : G_("%K%qD accessing between %E and %E "
- "bytes in a region of size %E")),
- exp, func, range[0], range[1],
- size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kmay access between %E and %E bytes "
- "in a region of size %E")
- : G_("%Kaccessing between %E and %E bytes "
- "in a region of size %E")),
- exp, range[0], range[1],
- size));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("may access between %E and %E bytes "
+ "in a region of size %E")
+ : G_("accessing between %E and %E bytes "
+ "in a region of size %E")),
+ range[0], range[1], size));
return warned;
}
@@ -4206,72 +4294,70 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
{
if (tree_int_cst_equal (range[0], range[1]))
warned = (func
- ? warning_n (loc, opt, tree_to_uhwi (range[0]),
+ ? warning_n (dic, opt, tree_to_uhwi (range[0]),
(maybe
- ? G_("%K%qD may write %E byte into a region "
+ ? G_("%qD may write %E byte into a region "
"of size %E")
- : G_("%K%qD writing %E byte into a region "
+ : G_("%qD writing %E byte into a region "
"of size %E overflows the destination")),
(maybe
- ? G_("%K%qD may write %E bytes into a region "
+ ? G_("%qD may write %E bytes into a region "
"of size %E")
- : G_("%K%qD writing %E bytes into a region "
+ : G_("%qD writing %E bytes into a region "
"of size %E overflows the destination")),
- exp, func, range[0], size)
- : warning_n (loc, opt, tree_to_uhwi (range[0]),
+ func, range[0], size)
+ : warning_n (dic, opt, tree_to_uhwi (range[0]),
(maybe
- ? G_("%Kmay write %E byte into a region "
+ ? G_("may write %E byte into a region "
"of size %E")
- : G_("%Kwriting %E byte into a region "
+ : G_("writing %E byte into a region "
"of size %E overflows the destination")),
(maybe
- ? G_("%Kmay write %E bytes into a region "
+ ? G_("may write %E bytes into a region "
"of size %E")
- : G_("%Kwriting %E bytes into a region "
+ : G_("writing %E bytes into a region "
"of size %E overflows the destination")),
- exp, range[0], size));
+ range[0], size));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD may write %E or more bytes "
- "into a region of size %E "
- "the destination")
- : G_("%K%qD writing %E or more bytes "
- "into a region of size %E overflows "
- "the destination")),
- exp, func, range[0], size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kmay write %E or more bytes into "
- "a region of size %E")
- : G_("%Kwriting %E or more bytes into "
- "a region of size %E overflows "
- "the destination")),
- exp, range[0], size));
+ ? warning (dic, opt,
+ (maybe
+ ? G_("%qD may write %E or more bytes "
+ "into a region of size %E "
+ "the destination")
+ : G_("%qD writing %E or more bytes "
+ "into a region of size %E overflows "
+ "the destination")),
+ func, range[0], size)
+ : warning (dic, opt,
+ (maybe
+ ? G_("may write %E or more bytes into "
+ "a region of size %E")
+ : G_("writing %E or more bytes into "
+ "a region of size %E overflows "
+ "the destination")),
+ range[0], size));
}
else
warned = (func
- ? warning_at (loc, opt,
- (maybe
- ? G_("%K%qD may write between %E and %E bytes "
- "into a region of size %E")
- : G_("%K%qD writing between %E and %E bytes "
- "into a region of size %E overflows "
- "the destination")),
- exp, func, range[0], range[1],
- size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kmay write between %E and %E bytes "
- "into a region of size %E")
- : G_("%Kwriting between %E and %E bytes "
- "into a region of size %E overflows "
- "the destination")),
- exp, range[0], range[1],
- size));
+ ? warning (dic, opt,
+ (maybe
+ ? G_("%qD may write between %E and %E bytes "
+ "into a region of size %E")
+ : G_("%qD writing between %E and %E bytes "
+ "into a region of size %E overflows "
+ "the destination")),
+ func, range[0], range[1], size)
+ : warning (dic, opt,
+ (maybe
+ ? G_("may write between %E and %E bytes "
+ "into a region of size %E")
+ : G_("writing between %E and %E bytes "
+ "into a region of size %E overflows "
+ "the destination")),
+ range[0], range[1], size));
return warned;
}
@@ -4279,67 +4365,67 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
{
if (tree_int_cst_equal (range[0], range[1]))
warned = (func
- ? warning_n (loc, OPT_Wstringop_overread,
+ ? warning_n (dic, OPT_Wstringop_overread,
tree_to_uhwi (range[0]),
(maybe
- ? G_("%K%qD may reade %E byte from a region "
+ ? G_("%qD may reade %E byte from a region "
"of size %E")
- : G_("%K%qD reading %E byte from a region "
+ : G_("%qD reading %E byte from a region "
"of size %E")),
(maybe
- ? G_("%K%qD may read %E bytes from a region "
+ ? G_("%qD may read %E bytes from a region "
"of size %E")
- : G_("%K%qD reading %E bytes from a region "
+ : G_("%qD reading %E bytes from a region "
"of size %E")),
- exp, func, range[0], size)
- : warning_n (loc, OPT_Wstringop_overread,
+ func, range[0], size)
+ : warning_n (dic, OPT_Wstringop_overread,
tree_to_uhwi (range[0]),
(maybe
- ? G_("%Kmay read %E byte from a region "
+ ? G_("may read %E byte from a region "
"of size %E")
- : G_("%Kreading %E byte from a region "
+ : G_("reading %E byte from a region "
"of size %E")),
(maybe
- ? G_("%Kmay read %E bytes from a region "
+ ? G_("may read %E bytes from a region "
"of size %E")
- : G_("%Kreading %E bytes from a region "
+ : G_("reading %E bytes from a region "
"of size %E")),
- exp, range[0], size));
+ range[0], size));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warned = (func
- ? warning_at (loc, OPT_Wstringop_overread,
- (maybe
- ? G_("%K%qD may read %E or more bytes "
- "from a region of size %E")
- : G_("%K%qD reading %E or more bytes "
- "from a region of size %E")),
- exp, func, range[0], size)
- : warning_at (loc, OPT_Wstringop_overread,
- (maybe
- ? G_("%Kmay read %E or more bytes "
- "from a region of size %E")
- : G_("%Kreading %E or more bytes "
- "from a region of size %E")),
- exp, range[0], size));
+ ? warning (dic, 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 (dic, OPT_Wstringop_overread,
+ (maybe
+ ? G_("may read %E or more bytes "
+ "from a region of size %E")
+ : G_("reading %E or more bytes "
+ "from a region of size %E")),
+ range[0], size));
}
else
warned = (func
- ? warning_at (loc, OPT_Wstringop_overread,
- (maybe
- ? G_("%K%qD may read between %E and %E bytes "
- "from a region of size %E")
- : G_("%K%qD reading between %E and %E bytes "
- "from a region of size %E")),
- exp, func, range[0], range[1], size)
- : warning_at (loc, opt,
- (maybe
- ? G_("%Kmay read between %E and %E bytes "
- "from a region of size %E")
- : G_("%Kreading between %E and %E bytes "
- "from a region of size %E")),
- exp, range[0], range[1], size));
+ ? warning (dic, 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 (dic, opt,
+ (maybe
+ ? G_("may read between %E and %E bytes "
+ "from a region of size %E")
+ : G_("reading between %E and %E bytes "
+ "from a region of size %E")),
+ range[0], range[1], size));
if (warned)
TREE_NO_WARNING (exp) = true;
@@ -4350,39 +4436,39 @@ warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
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 (dic, OPT_Wstringop_overread,
tree_to_uhwi (range[0]),
- "%K%qD epecting %E byte in a region of size %E",
- "%K%qD expecting %E bytes in a region of size %E",
- exp, func, range[0], size)
- : warning_n (loc, OPT_Wstringop_overread,
+ "%qD epecting %E byte in a region of size %E",
+ "%qD expecting %E bytes in a region of size %E",
+ func, range[0], size)
+ : warning_n (dic, OPT_Wstringop_overread,
tree_to_uhwi (range[0]),
- "%Kexpecting %E byte in a region of size %E",
- "%Kexpecting %E bytes in a region of size %E",
- exp, range[0], size));
+ "expecting %E byte in a region of size %E",
+ "expecting %E bytes in a region of size %E",
+ range[0], size));
else if (tree_int_cst_sign_bit (range[1]))
{
/* Avoid printing the upper bound if it's invalid. */
warned = (func
- ? warning_at (loc, OPT_Wstringop_overread,
- "%K%qD expecting %E or more bytes in a region "
- "of size %E",
- exp, func, range[0], size)
- : warning_at (loc, OPT_Wstringop_overread,
- "%Kexpecting %E or more bytes in a region "
- "of size %E",
- exp, range[0], size));
+ ? warning (dic, OPT_Wstringop_overread,
+ "%qD expecting %E or more bytes in a region "
+ "of size %E",
+ func, range[0], size)
+ : warning (dic, 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,
- "%K%qD expecting between %E and %E bytes in "
- "a region of size %E",
- exp, func, range[0], range[1], size)
- : warning_at (loc, OPT_Wstringop_overread,
- "%Kexpectting between %E and %E bytes in "
- "a region of size %E",
- exp, range[0], range[1], size));
+ ? warning (dic, OPT_Wstringop_overread,
+ "%qD expecting between %E and %E bytes in "
+ "a region of size %E",
+ func, range[0], range[1], size)
+ : warning (dic, OPT_Wstringop_overread,
+ "expectting between %E and %E bytes in "
+ "a region of size %E",
+ range[0], range[1], size));
if (warned)
TREE_NO_WARNING (exp) = true;
@@ -4575,9 +4661,11 @@ access_ref::inform_access (access_mode mode) const
inform (loc,
"at offset %s into source object of size %s allocated by %qE",
offstr, sizestr, allocfn);
- else
+ else if (allocfn)
inform (loc, "source object of size %s allocated by %qE",
sizestr, allocfn);
+ else
+ inform (loc, "source object of size %s allocated here", sizestr);
}
/* Helper to set RANGE to the range of BOUND if it's nonnull, bounded
@@ -4742,8 +4830,7 @@ check_access (tree exp, tree dstwrite,
&& TREE_CODE (range[0]) == INTEGER_CST
&& tree_int_cst_lt (maxobjsize, range[0]))
{
- location_t loc = tree_inlined_location (exp);
- maybe_warn_for_bound (OPT_Wstringop_overflow_, loc, exp, func, range,
+ maybe_warn_for_bound (OPT_Wstringop_overflow_, exp, func, range,
NULL_TREE, pad);
return false;
}
@@ -4768,24 +4855,24 @@ check_access (tree exp, tree dstwrite,
|| (pad && pad->dst.ref && TREE_NO_WARNING (pad->dst.ref)))
return false;
- location_t loc = tree_inlined_location (exp);
bool warned = false;
if (dstwrite == slen && at_least_one)
{
+ diag_inlining_context dic (exp);
/* This is a call to strcpy with a destination of 0 size
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_Wstringop_overflow_,
- "%K%qD writing %E or more bytes into "
- "a region of size %E overflows "
- "the destination",
- exp, func, range[0], dstsize)
- : warning_at (loc, OPT_Wstringop_overflow_,
- "%Kwriting %E or more bytes into "
- "a region of size %E overflows "
- "the destination",
- exp, range[0], dstsize));
+ ? warning (dic, OPT_Wstringop_overflow_,
+ "%qD writing %E or more bytes into "
+ "a region of size %E overflows "
+ "the destination",
+ func, range[0], dstsize)
+ : warning (dic, OPT_Wstringop_overflow_,
+ "writing %E or more bytes into "
+ "a region of size %E overflows "
+ "the destination",
+ range[0], dstsize));
}
else
{
@@ -4794,8 +4881,7 @@ check_access (tree exp, tree dstwrite,
const bool write
= mode == access_write_only || mode == access_read_write;
const bool maybe = pad && pad->dst.parmarray;
- warned = warn_for_access (loc, func, exp,
- OPT_Wstringop_overflow_,
+ warned = warn_for_access (func, exp, OPT_Wstringop_overflow_,
range, dstsize,
write, read && !builtin, maybe);
}
@@ -4821,7 +4907,6 @@ check_access (tree exp, tree dstwrite,
PAD is nonnull and BNDRNG is valid. */
get_size_range (maxread, range, pad ? pad->src.bndrng : NULL);
- location_t loc = tree_inlined_location (exp);
tree size = dstsize;
if (pad && pad->mode == access_read_only)
size = wide_int_to_tree (sizetype, pad->src.sizrng[1]);
@@ -4830,7 +4915,7 @@ check_access (tree exp, tree dstwrite,
{
if (tree_int_cst_lt (maxobjsize, range[0]))
{
- maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+ maybe_warn_for_bound (OPT_Wstringop_overread, exp, func,
range, size, pad);
return false;
}
@@ -4840,7 +4925,7 @@ check_access (tree exp, tree dstwrite,
int opt = (dstwrite || mode != access_read_only
? OPT_Wstringop_overflow_
: OPT_Wstringop_overread);
- maybe_warn_for_bound (opt, loc, exp, func, range, size, pad);
+ maybe_warn_for_bound (opt, exp, func, range, size, pad);
return false;
}
}
@@ -4880,11 +4965,10 @@ check_access (tree exp, tree dstwrite,
|| (pad && pad->src.ref && TREE_NO_WARNING (pad->src.ref)))
return false;
- location_t loc = tree_inlined_location (exp);
const bool read
= mode == access_read_only || mode == access_read_write;
const bool maybe = pad && pad->dst.parmarray;
- if (warn_for_access (loc, func, exp, OPT_Wstringop_overread, range,
+ if (warn_for_access (func, exp, OPT_Wstringop_overread, range,
slen, false, read, maybe))
{
TREE_NO_WARNING (exp) = true;
@@ -7070,13 +7154,13 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
offset_int rem1 = ref1.size_remaining ();
offset_int rem2 = ref2.size_remaining ();
if (rem1 == 0 || rem2 == 0)
- maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+ maybe_warn_for_bound (OPT_Wstringop_overread, exp, func,
bndrng, integer_zero_node);
else
{
offset_int maxrem = wi::max (rem1, rem2, UNSIGNED);
if (maxrem < wi::to_offset (bndrng[0]))
- maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp,
+ maybe_warn_for_bound (OPT_Wstringop_overread, exp,
func, bndrng,
wide_int_to_tree (sizetype, maxrem));
}
@@ -7085,7 +7169,7 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
&& !integer_zerop (bndrng[0])
&& ((size1 && integer_zerop (size1))
|| (size2 && integer_zerop (size2))))
- maybe_warn_for_bound (OPT_Wstringop_overread, loc, exp, func,
+ maybe_warn_for_bound (OPT_Wstringop_overread, exp, func,
bndrng, integer_zero_node);
}
}
@@ -13439,7 +13523,7 @@ matching_alloc_calls_p (gimple *alloc, tree dealloc_decl)
the target pointer is unknown. */
static bool
-warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref)
+warn_dealloc_offset (tree exp, const access_ref &aref)
{
if (aref.deref || aref.offrng[0] <= 0 || aref.offrng[1] <= 0)
return false;
@@ -13480,9 +13564,10 @@ warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref)
(long long)aref.offrng[1].to_shwi ());
}
- if (!warning_at (loc, OPT_Wfree_nonheap_object,
- "%K%qD called on pointer %qE with nonzero offset%s",
- exp, dealloc_decl, aref.ref, offstr))
+ diag_inlining_context dic (exp);
+ if (!warning (dic, OPT_Wfree_nonheap_object,
+ "%qD called on pointer %qE with nonzero offset%s",
+ dealloc_decl, aref.ref, offstr))
return false;
if (DECL_P (aref.ref))
@@ -13537,19 +13622,20 @@ maybe_emit_free_warning (tree exp)
return;
tree dealloc_decl = get_callee_fndecl (exp);
- location_t loc = tree_inlined_location (exp);
if (DECL_P (ref) || EXPR_P (ref))
{
+ diag_inlining_context dic (exp);
+
/* Diagnose freeing a declared object. */
if (aref.ref_declared ()
- && warning_at (loc, OPT_Wfree_nonheap_object,
- "%K%qD called on unallocated object %qD",
- exp, dealloc_decl, ref))
+ && warning (dic, OPT_Wfree_nonheap_object,
+ "%qD called on unallocated object %qD",
+ dealloc_decl, ref))
{
- loc = (DECL_P (ref)
- ? DECL_SOURCE_LOCATION (ref)
- : EXPR_LOCATION (ref));
+ location_t loc = (DECL_P (ref)
+ ? DECL_SOURCE_LOCATION (ref)
+ : EXPR_LOCATION (ref));
inform (loc, "declared here");
return;
}
@@ -13558,14 +13644,15 @@ maybe_emit_free_warning (tree exp)
Such a pointer cannot refer to the beginning of an allocated
object. A negative offset may refer to it. */
if (aref.sizrng[0] != aref.sizrng[1]
- && warn_dealloc_offset (loc, exp, aref))
+ && warn_dealloc_offset (exp, aref))
return;
}
else if (CONSTANT_CLASS_P (ref))
{
- if (warning_at (loc, OPT_Wfree_nonheap_object,
- "%K%qD called on a pointer to an unallocated "
- "object %qE", exp, dealloc_decl, ref))
+ diag_inlining_context dic (exp);
+ if (warning (dic, OPT_Wfree_nonheap_object,
+ "%qD called on a pointer to an unallocated "
+ "object %qE", dealloc_decl, ref))
{
if (TREE_CODE (ptr) == SSA_NAME)
{
@@ -13591,7 +13678,7 @@ maybe_emit_free_warning (tree exp)
{
if (matching_alloc_calls_p (def_stmt, dealloc_decl))
{
- if (warn_dealloc_offset (loc, exp, aref))
+ if (warn_dealloc_offset (exp, aref))
return;
}
else
@@ -13601,20 +13688,24 @@ maybe_emit_free_warning (tree exp)
|| DECL_IS_OPERATOR_DELETE_P (dealloc_decl)
? OPT_Wmismatched_new_delete
: OPT_Wmismatched_dealloc);
- warned = warning_at (loc, opt,
- "%K%qD called on pointer returned "
- "from a mismatched allocation "
- "function", exp, dealloc_decl);
+ diag_inlining_context dic (exp);
+ warned = warning (dic, opt,
+ "%qD called on pointer returned "
+ "from a mismatched allocation "
+ "function", dealloc_decl);
}
}
else if (gimple_call_builtin_p (def_stmt, BUILT_IN_ALLOCA)
|| gimple_call_builtin_p (def_stmt,
BUILT_IN_ALLOCA_WITH_ALIGN))
- warned = warning_at (loc, OPT_Wfree_nonheap_object,
- "%K%qD called on pointer to "
- "an unallocated object",
- exp, dealloc_decl);
- else if (warn_dealloc_offset (loc, exp, aref))
+ {
+ diag_inlining_context dic (exp);
+ warned = warning (dic, OPT_Wfree_nonheap_object,
+ "%qD called on pointer to "
+ "an unallocated object",
+ dealloc_decl);
+ }
+ else if (warn_dealloc_offset (exp, aref))
return;
if (warned)
@@ -13633,7 +13724,7 @@ maybe_emit_free_warning (tree exp)
&& !aref.deref
&& aref.sizrng[0] != aref.sizrng[1]
&& aref.offrng[0] > 0 && aref.offrng[1] > 0
- && warn_dealloc_offset (loc, exp, aref))
+ && warn_dealloc_offset (exp, aref))
return;
}
}
diff --git a/gcc/cp/mapper-client.cc b/gcc/cp/mapper-client.cc
index a72b4b70664..368e88201fa 100644
--- a/gcc/cp/mapper-client.cc
+++ b/gcc/cp/mapper-client.cc
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_STRING
#define INCLUDE_VECTOR
#include "system.h"
-
+#include "coretypes.h"
#include "line-map.h"
#include "diagnostic-core.h"
#include "mapper-client.h"
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index 60fe8a27f44..cdf70ddfb46 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_DIAGNOSTIC_CORE_H
#include "bversion.h"
+#include "diagnostic-metadata.h"
/* Constants used to discriminate diagnostics. */
typedef enum
@@ -81,6 +82,16 @@ extern bool warning_at (location_t, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at (rich_location *, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
+
+/* Same as warning_at but with contextual informaion provided by first
+ argument. */
+extern bool warning (diagnostic_metadata::location_context&, int,
+ const char *, ...)
+ ATTRIBUTE_GCC_DIAG (3, 4);
+extern bool warning_n (diagnostic_metadata::location_context&, int,
+ unsigned HOST_WIDE_INT, const char *, const char *, ...)
+ ATTRIBUTE_GCC_DIAG (4, 6) ATTRIBUTE_GCC_DIAG (5, 6);
+
extern bool warning_meta (rich_location *,
const diagnostic_metadata &, int,
const char *, ...)
diff --git a/gcc/diagnostic-metadata.h b/gcc/diagnostic-metadata.h
index fe10304e05e..db49cff72b9 100644
--- a/gcc/diagnostic-metadata.h
+++ b/gcc/diagnostic-metadata.h
@@ -21,22 +21,45 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DIAGNOSTIC_METADATA_H
#define GCC_DIAGNOSTIC_METADATA_H
+#include "vec.h"
+
/* A bundle of additional metadata that can be associated with a
diagnostic.
- Currently this only supports associating a CWE identifier with a
- diagnostic. */
+ Currently this only supports associating a location context and
+ a CWE identifier with a diagnostic. */
class diagnostic_metadata
{
public:
- diagnostic_metadata () : m_cwe (0) {}
+ class location_context;
+
+ diagnostic_metadata () : m_lctx (), m_cwe (0) {}
+
+ diagnostic_metadata (location_context &lctx)
+ : m_lctx (&lctx), m_cwe () {}
void add_cwe (int cwe) { m_cwe = cwe; }
int get_cwe () const { return m_cwe; }
+ location_context* location_ctx () const { return m_lctx; }
+
private:
+ /* The context of the expression the diagnostic is issued for. For
+ front end diagnostics it's empty. For middle end diagnostics it
+ includes the inlining context (implemented in a derived class). */
+ location_context *m_lctx;
int m_cwe;
};
+struct diagnostic_info;
+
+class diagnostic_metadata::location_context
+{
+public:
+ virtual void locations (vec<location_t> &, diagnostic_info *);
+ virtual void set_location (diagnostic_info *) { }
+};
+
+
#endif /* ! GCC_DIAGNOSTIC_METADATA_H */
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 246d75256cf..d82a7eb67e5 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "selftest-diagnostic.h"
#include "opts.h"
#include "cpplib.h"
+#include "tree.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
@@ -991,51 +992,81 @@ print_parseable_fixits (pretty_printer *pp, rich_location *richloc,
pp_set_prefix (pp, saved_prefix);
}
-/* Update the diag_class of DIAGNOSTIC based on its location
- relative to any
+/* Add DIAGNOSTIC location to LOCS. */
+
+/* virtual */ void
+diagnostic_metadata::
+location_context::locations (vec<location_t> &locs, diagnostic_info *di)
+{
+ locs.safe_push (diagnostic_location (di));
+}
+
+
+/* Update the kind of DIAGNOSTIC based on its location(s), including
+ any of those in its inlining context, relative to any
#pragma GCC diagnostic
directives recorded within CONTEXT.
- Return the new diag_class of DIAGNOSTIC if it was updated, or
- DK_UNSPECIFIED otherwise. */
+ Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
+ otherwise. */
static diagnostic_t
update_effective_level_from_pragmas (diagnostic_context *context,
diagnostic_info *diagnostic)
{
- diagnostic_t diag_class = DK_UNSPECIFIED;
-
if (context->n_classification_history > 0)
{
- location_t location = diagnostic_location (diagnostic);
-
- /* FIXME: Stupid search. Optimize later. */
- for (int i = context->n_classification_history - 1; i >= 0; i --)
+ auto_vec<location_t, 8> locs;
+ diagnostic_metadata::location_context *lctx = NULL;
+ if (const diagnostic_metadata *mdata = diagnostic->metadata)
+ lctx = mdata->location_ctx ();
+
+ if (lctx)
+ /* Retrieve the locations into which the expression about to be
+ diagnosed has been inlined, including those of all the callers
+ all the way down the inlining stack. */
+ lctx->locations (locs, diagnostic);
+ else
+ /* When there's no metadata use just the one location provided
+ by the caller of the diagnostic function. */
+ locs.safe_push (diagnostic_location (diagnostic));
+
+ /* Iterate over the locations, checking the diagnostic disposition
+ for the diagnostic at each. If it's explicitly set as opposed
+ to unspecified, update the disposition for this instance of
+ the diagnostic and return it. */
+ for (unsigned idx = 0; idx < locs.length (); ++idx)
{
- if (linemap_location_before_p
- (line_table,
- context->classification_history[i].location,
- location))
+ /* FIXME: Stupid search. Optimize later. */
+ for (int i = context->n_classification_history - 1; i >= 0; i --)
{
- if (context->classification_history[i].kind == (int) DK_POP)
- {
- i = context->classification_history[i].option;
- continue;
- }
- int option = context->classification_history[i].option;
- /* The option 0 is for all the diagnostics. */
- if (option == 0 || option == diagnostic->option_index)
+ const diagnostic_classification_change_t &hist
+ = context->classification_history[i];
+
+ location_t pragloc = hist.location;
+ if (linemap_location_before_p (line_table, pragloc, locs[idx]))
{
- diag_class = context->classification_history[i].kind;
- if (diag_class != DK_UNSPECIFIED)
- diagnostic->kind = diag_class;
- break;
+ if (hist.kind == (int) DK_POP)
+ {
+ /* Move on to the next region. */
+ i = hist.option;
+ continue;
+ }
+ int option = hist.option;
+ /* The option 0 is for all the diagnostics. */
+ if (option == 0 || option == diagnostic->option_index)
+ {
+ diagnostic_t kind = hist.kind;
+ if (kind != DK_UNSPECIFIED)
+ diagnostic->kind = kind;
+ return kind;
+ }
}
}
}
}
- return diag_class;
+ return DK_UNSPECIFIED;
}
/* Generate a URL string describing CWE. The caller is responsible for
@@ -1239,8 +1270,14 @@ diagnostic_report_diagnostic (diagnostic_context *context,
}
context->diagnostic_group_emission_count++;
+ /* Move X_DATA into DIAGNOSTIC->MESSAGE before setting inlining context
+ abstract origin and location. It uses X_DATA. */
diagnostic->message.x_data = &diagnostic->x_data;
diagnostic->x_data = NULL;
+ if (const diagnostic_metadata *mdata = diagnostic->metadata)
+ if (diagnostic_metadata::location_context *lctx = mdata->location_ctx ())
+ lctx->set_location (diagnostic);
+
pp_format (context->printer, &diagnostic->message);
(*diagnostic_starter (context)) (context, diagnostic);
pp_output_formatted_text (context->printer);
@@ -1389,7 +1426,7 @@ diagnostic_impl (rich_location *richloc, const diagnostic_metadata *metadata,
int opt, const char *gmsgid,
va_list *ap, diagnostic_t kind)
{
- diagnostic_info diagnostic;
+ diagnostic_info diagnostic{ };
if (kind == DK_PERMERROR)
{
diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
@@ -1415,7 +1452,7 @@ diagnostic_n_impl (rich_location *richloc, const diagnostic_metadata *metadata,
const char *plural_gmsgid,
va_list *ap, diagnostic_t kind)
{
- diagnostic_info diagnostic;
+ diagnostic_info diagnostic{ };
unsigned long gtn;
if (sizeof n <= sizeof gtn)
@@ -1616,6 +1653,46 @@ warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
return ret;
}
+/* A warning at location and context provided by first argument. Same
+ as warning_at() with location_t except that it doesn't require %K (or
+ in the future %G). */
+
+bool
+warning (diagnostic_metadata::location_context &lctx, int opt,
+ const char *gmsgid, ...)
+{
+ auto_diagnostic_group d;
+ va_list ap;
+ va_start (ap, gmsgid);
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ diagnostic_metadata mdata (lctx);
+ bool ret = diagnostic_impl (&richloc, &mdata, opt, gmsgid,
+ &ap, DK_WARNING);
+ va_end (ap);
+ return ret;
+}
+
+/* A warning at location and context provided by first argument. Same
+ as warning_n() with location_t except that it doesn't require %K (or
+ in the future %G). */
+
+bool
+warning_n (diagnostic_metadata::location_context &lctx, int opt,
+ unsigned HOST_WIDE_INT n,
+ const char *singular_gmsgid, const char *plural_gmsgid, ...)
+{
+ auto_diagnostic_group d;
+ va_list ap;
+ va_start (ap, plural_gmsgid);
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ diagnostic_metadata mdata (lctx);
+ bool ret = diagnostic_n_impl (&richloc, &mdata, opt, n,
+ singular_gmsgid, plural_gmsgid,
+ &ap, DK_WARNING);
+ va_end (ap);
+ return ret;
+}
+
/* A "pedantic" warning at LOCATION: issues a warning unless
-pedantic-errors was given on the command line, in which case it
issues an error. Use this for diagnostics required by the relevant
diff --git a/gcc/testsuite/gcc.dg/pragma-diag-10.c b/gcc/testsuite/gcc.dg/pragma-diag-10.c
new file mode 100644
index 00000000000..127b299939a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pragma-diag-10.c
@@ -0,0 +1,20 @@
+/* PR middle-end/98512 - #pragma GCC diagnostic ignored ineffective
+ in conjunction with alias attribute
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+void *
+__rawmemchr_ppc (const void *s, int c)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#pragma GCC diagnostic ignored "-Wstringop-overread"
+ if (c != 0)
+ return __builtin_memchr (s, c, (unsigned long)-1); // { dg-bogus "specified bound \\d+ exceeds maximum object size" }
+#pragma GCC diagnostic pop
+
+ return (char *)s + __builtin_strlen (s);
+}
+
+extern __typeof (__rawmemchr_ppc) __EI___rawmemchr_ppc
+ __attribute__((alias ("__rawmemchr_ppc")));
diff --git a/gcc/testsuite/gcc.dg/pragma-diag-9.c b/gcc/testsuite/gcc.dg/pragma-diag-9.c
new file mode 100644
index 00000000000..d7eac558128
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pragma-diag-9.c
@@ -0,0 +1,134 @@
+/* Verify that #pragma GCC diagnostic down the inlining stack suppresses
+ a warning that would otherwise be issued for inlined calls higher up
+ the inlining stack.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -Wno-array-bounds" } */
+
+extern void* memset (void*, int, __SIZE_TYPE__);
+
+static void warn0 (int *p)
+{
+ memset (p, __LINE__, 3); // { dg-warning "\\\[-Wstringop-overflow" }
+}
+
+static void warn1 (int *p)
+{
+ warn0 (p + 1);
+}
+
+static void warn2 (int *p)
+{
+ warn1 (p + 1);
+}
+
+int a2[2]; // { dg-message "at offset 12 into destination object 'a2' of size 8" }
+
+void warn3 (void)
+{
+ warn2 (a2 + 1);
+}
+
+
+static void ignore0 (int *p)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ memset (p, __LINE__, 3);
+#pragma GCC diagnostic pop
+}
+
+static void nowarn1_ignore0 (int *p)
+{
+ ignore0 (p + 1);
+}
+
+static void nowarn2_ignore0 (int *p)
+{
+ nowarn1_ignore0 (p + 1);
+}
+
+int b2[2];
+
+void nowarn3_ignore0 (void)
+{
+ nowarn2_ignore0 (b2 + 1);
+}
+
+
+static void nowarn0_ignore1 (int *p)
+{
+ memset (p, __LINE__, 3);
+}
+
+static void ignore1 (int *p)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ nowarn0_ignore1 (p + 1);
+#pragma GCC diagnostic pop
+}
+
+void nowarn2_ignore1 (int *p)
+{
+ ignore1 (p + 1);
+}
+
+int c2[2];
+
+void nowarn3_ignore1 (void)
+{
+ nowarn2_ignore1 (c2 + 1);
+}
+
+
+static void nowarn0_ignore2 (int *p)
+{
+ memset (p, __LINE__, 3);
+}
+
+static void nowarn1_ignore2 (int *p)
+{
+ nowarn0_ignore2 (p + 1);
+}
+
+static void ignore2 (int *p)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ nowarn1_ignore2 (p + 1);
+#pragma GCC diagnostic pop
+}
+
+int d2[2];
+
+void nowarn3_ignore2 (void)
+{
+ ignore2 (c2 + 1);
+}
+
+
+
+static void nowarn0_ignore3 (int *p)
+{
+ memset (p, __LINE__, 3);
+}
+
+static void nowarn1_ignore3 (int *p)
+{
+ nowarn0_ignore3 (p + 1);
+}
+
+static void nowarn2_ignore3 (int *p)
+{
+ nowarn1_ignore3 (p + 1);
+}
+
+int e2[2];
+
+void ignore3 (void)
+{
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ nowarn2_ignore3 (e2 + 1);
+#pragma GCC diagnostic pop
+}
diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc
index 5beda8b829b..c3faa6bfde4 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -468,6 +468,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
else
{
+ /* Suppress false positives when GCC can't determine that
+ __s doesn't alias _M_data(). */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#pragma GCC diagnostic ignored "-Wstringop-overread"
// Work in-place.
if (__len2 && __len2 <= __len1)
this->_S_move(__p, __s, __len2);
@@ -488,6 +493,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
}
+#pragma GCC diagnostic pop
}
else
this->_M_mutate(__pos, __len1, __s, __len2);
diff --git a/libstdc++-v3/testsuite/18_support/new_delete_placement.cc b/libstdc++-v3/testsuite/18_support/new_delete_placement.cc
index e4f747606cd..1d188f6edd8 100644
--- a/libstdc++-v3/testsuite/18_support/new_delete_placement.cc
+++ b/libstdc++-v3/testsuite/18_support/new_delete_placement.cc
@@ -32,6 +32,8 @@ void test01()
operator delete[](p, tmp);
}
+// { dg-prune-output "\\\[-Wfree-nonheap-object" }
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc
index 95d512d4b82..55973992837 100644
--- a/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc
+++ b/libstdc++-v3/testsuite/20_util/monotonic_buffer_resource/allocate.cc
@@ -15,7 +15,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17" }
+// { dg-options "-std=gnu++17 -Wno-alloc-size-larger-than" }
// { dg-do run { target c++17 } }
// { dg-require-cstdint "" }
diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
index 79fac01fb25..fab73838f38 100644
--- a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
+++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/allocate.cc
@@ -15,7 +15,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-options "-std=gnu++17" }
+// { dg-options "-std=gnu++17 -Wno-alloc-size-larger-than" }
// { dg-do run { target c++17 } }
#include <memory_resource>
next prev parent reply other threads:[~2021-01-21 23:46 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-19 18:58 Martin Sebor
2021-01-21 17:34 ` Florian Weimer
2021-01-21 18:24 ` Martin Sebor
2021-01-21 19:01 ` Florian Weimer
2021-01-21 20:24 ` Martin Sebor
2021-01-21 23:46 ` Martin Sebor [this message]
2021-01-30 2:56 ` PING " Martin Sebor
2021-02-06 17:12 ` PING 2 " Martin Sebor
2021-02-15 0:40 ` PING 3 " Martin Sebor
2021-05-19 13:41 ` David Malcolm
2021-06-10 23:24 ` [PATCH 0/4] improve warning suppression for inlined functions (PR 98512) Martin Sebor
2021-06-10 23:26 ` [PATCH 1/4] introduce diagnostic infrastructure changes " Martin Sebor
2021-06-11 17:04 ` David Malcolm
2021-06-15 23:00 ` Martin Sebor
2021-06-28 18:10 ` [PING][PATCH " Martin Sebor
2021-06-30 22:55 ` [PATCH " David Malcolm
2021-07-01 19:43 ` Martin Sebor
2021-06-10 23:27 ` [PATCH 2/4] remove %G and %K from calls in front end and middle end " Martin Sebor
2021-06-30 15:39 ` [PING][PATCH " Martin Sebor
2021-06-30 19:45 ` Martin Sebor
2021-06-30 23:35 ` David Malcolm
2021-07-01 20:14 ` Martin Sebor
2021-07-02 6:56 ` Aldy Hernandez
2021-07-02 21:53 ` Jeff Law
2021-07-02 20:52 ` David Malcolm
2021-07-02 22:15 ` Martin Sebor
2021-06-10 23:28 ` [PATCH 3/4] remove %K from error() calls in the aarch64/arm back ends " Martin Sebor
2021-06-11 7:53 ` Christophe Lyon
2021-06-11 13:10 ` Christophe Lyon
2021-06-11 14:47 ` Martin Sebor
2021-06-11 9:58 ` Richard Sandiford
2021-06-11 14:46 ` Martin Sebor
2021-06-30 19:56 ` Martin Sebor
2021-07-01 8:01 ` Christophe LYON
2021-07-01 14:45 ` Martin Sebor
2021-06-10 23:30 ` [PATCH 4/4] remove %G and %K support from pretty printer and -Wformat " Martin Sebor
2021-06-30 16:17 ` [PING][PATCH " Martin Sebor
2021-06-30 23:38 ` [PATCH " David Malcolm
2021-07-06 20:15 ` Martin Sebor
2021-07-07 9:38 ` Andreas Schwab
2021-07-07 9:47 ` Christophe Lyon
2021-07-07 10:12 ` Andreas Schwab
2021-02-19 4:28 ` [PATCH] improve warning suppression for inlined functions (PR 98465, 98512) Jeff Law
2021-02-19 10:57 ` Florian Weimer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=945093c7-de5e-0350-6030-e4e79ea41161@gmail.com \
--to=msebor@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).