public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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>

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