public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] improve warning suppression for inlined functions (PR 98465,  98512)
@ 2021-01-19 18:58 Martin Sebor
  2021-01-21 17:34 ` Florian Weimer
                   ` (2 more replies)
  0 siblings, 3 replies; 44+ messages in thread
From: Martin Sebor @ 2021-01-19 18:58 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2077 bytes --]

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: 53353 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.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index c1115a32d91..68f1ae042d8 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;
@@ -4572,9 +4658,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
@@ -4739,8 +4827,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;
     }
@@ -4765,24 +4852,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
 	    {
@@ -4791,8 +4878,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);
 	    }
@@ -4818,7 +4904,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]);
@@ -4827,7 +4912,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;
 	    }
@@ -4837,7 +4922,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;
 	    }
 	}
@@ -4877,11 +4962,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;
@@ -7067,13 +7151,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));
 		}
@@ -7082,7 +7166,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);
 	}
     }
@@ -13436,7 +13520,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;
@@ -13477,9 +13561,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))
@@ -13534,19 +13619,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;
 	}
@@ -13555,14 +13641,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)
 	    {
@@ -13588,7 +13675,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
@@ -13598,20 +13685,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)
@@ -13630,7 +13721,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..abcd991b829 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);
@@ -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-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>

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2021-07-07 10:12 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-19 18:58 [PATCH] improve warning suppression for inlined functions (PR 98465, 98512) 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
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

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).