[PING] Don't maintain a warning spec for 'UNKNOWN_LOCATION'/'BUILTINS_LOCATION' [PR101574] (was: [PATCH 1/13] v2 [PATCH 1/13] Add support for per-location warning groups (PR 74765))

Message ID 87tuisub5r.fsf@euler.schwinge.homeip.net
State New
Headers show
Series
  • [PING] Don't maintain a warning spec for 'UNKNOWN_LOCATION'/'BUILTINS_LOCATION' [PR101574] (was: [PATCH 1/13] v2 [PATCH 1/13] Add support for per-location warning groups (PR 74765))
Related show

Commit Message

Thomas Schwinge Sept. 10, 2021, 7:45 a.m.
Hi!

Ping.

On 2021-09-03T21:16:46+0200, Thomas Schwinge <thomas@codesourcery.com> wrote:
> Martin, thanks for your review.  Now need someone to formally approve the

> third patch.


Again attached for easy reference.


Grüße
 Thomas


> On 2021-09-01T18:14:46-0600, Martin Sebor <msebor@gmail.com> wrote:

>> On 9/1/21 1:35 PM, Thomas Schwinge wrote:

>>> On 2021-06-23T13:47:08-0600, Martin Sebor via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:

>>>> On 6/22/21 5:28 PM, David Malcolm wrote:

>>>>> On Tue, 2021-06-22 at 19:18 -0400, David Malcolm wrote:

>>>>>> On Fri, 2021-06-04 at 15:41 -0600, Martin Sebor wrote:

>>>>>>> The attached patch introduces the suppress_warning(),

>>>>>>> warning_suppressed(), and copy_no_warning() APIs [etc.]

>

>>> I now had a bit of a deep dive into some aspects of this, in context of

>>> <https://gcc.gnu.org/PR101574> "gcc/sparseset.h:215:20: error: suggest

>>> parentheses around assignment used as truth value [-Werror=parentheses]"

>>> that I recently filed.  This seems difficult to reproduce, but I'm still

>>> able to reliably reproduce it in one specific build

>>> configuration/directory/machine/whatever.  Initially, we all quickly

>>> assumed that it'd be some GC issue -- but "alas", it's not, at least not

>>> directly.  (But I'll certainly assume that some GC aspects are involved

>>> which make this issue come and go across different GCC sources revisions,

>>> and difficult to reproduce.)

>

>>> First, two pieces of cleanup:

>

> ACKed by Martin, again attached for convenience.

>

>

>>>> --- /dev/null

>>>> +++ b/gcc/diagnostic-spec.h

>>>

>>>> +typedef location_t key_type_t;

>>>> +typedef int_hash <key_type_t, 0, UINT_MAX> xint_hash_t;

>

>> By the way, it seems we should probably also use a manifest constant

>> for Empty (probably UNKNOWN_LOCATION since we're reserving it).

>

> Yes, that will be part of another patch here -- waiting for approval of

> "Generalize 'gcc/input.h:struct location_hash'" posted elsewhere.

>

>

>>> attached "Don't maintain a warning spec for

>>> 'UNKNOWN_LOCATION'/'BUILTINS_LOCATION' [PR101574]".  OK to push?

>>

>> [...].  So I agree that it ought to be fixed.

>

>>> I'm reasonably confident that my changes are doing the right things in

>>> general, but please carefully review, especially here:

>>>

>>>    - 'gcc/warning-control.cc:suppress_warning' functions: is it correct to

>>>      conditionalize on '!RESERVED_LOCATION_P' the 'suppress_warning_at'

>>>      calls and 'supp' update?  Or, should instead 'suppress_warning_at'

>>>      handle the case of '!RESERVED_LOCATION_P'?  (How?)

>>

>> It seems like six of one vs half a dozen of the other.  I'd say go

>> with whatever makes more sense to you here :)

>

> OK, was just trying to make sure that I don't fail to see any non-obvious

> intentions here.

>

>>>    - 'gcc/diagnostic-spec.c:copy_warning' and

>>>      'gcc/warning-control.cc:copy_warning': is the rationale correct for

>>>      the 'gcc_checking_assert (!from_spec)': "If we cannot set no-warning

>>>      dispositions for 'to', ascertain that we don't have any for 'from'.

>>>      Otherwise, we'd lose these."?  If the rationale is correct, then

>>>      observing that in 'gcc/warning-control.cc:copy_warning' this

>>>      currently "triggers during GCC build" is something to be looked into,

>>>      later, I suppose, and otherwise, how should I change this code?

>>

>> copy_warning(location_t, location_t) is called [only] from

>> gimple_set_location().  The middle end does clear the location of

>> some statements for which it was previously valid (e.g., return

>> statements).

>

> What I observed was that the 'assert' never triggered for the

> 'location_t' variant "called [only] from gimple_set_location" -- but does

> trigger for some other variant.  Anyway:

>

>> So I wouldn't expect this assumption to be safe.  If

>> that happens, we have no choice but to lose the per-warning detail

>> and fall back on the no-warning bit.

>

> ACK.  I'm thus clarifying that as follows:

>

>     --- gcc/diagnostic-spec.c

>     +++ gcc/diagnostic-spec.c

>     @@ -185,7 +185,5 @@ copy_warning (location_t to, location_t from)

>        if (RESERVED_LOCATION_P (to))

>     -    {

>     -      /* If we cannot set no-warning dispositions for 'to', ascertain that we

>     -    don't have any for 'from'.  Otherwise, we'd lose these.  */

>     -      gcc_checking_assert (!from_spec);

>     -    }

>     +    /* We cannot set no-warning dispositions for 'to', so we have no chance but

>     +       lose those potentially set for 'from'.  */

>     +    ;

>        else

>     --- gcc/warning-control.cc

>     +++ gcc/warning-control.cc

>     @@ -197,9 +197,5 @@ void copy_warning (ToType to, FromType from)

>        if (RESERVED_LOCATION_P (to_loc))

>     -    {

>     -#if 0 //TODO triggers during GCC build

>     -      /* If we cannot set no-warning dispositions for 'to', ascertain that we

>     -    don't have any for 'from'.  Otherwise, we'd lose these.  */

>     -      gcc_checking_assert (!from_spec);

>     -#endif

>     -    }

>     +    /* We cannot set no-warning dispositions for 'to', so we have no chance but

>     +       lose those potentially set for 'from'.  */

>     +    ;

>        else

>

>> (Either David or a middle end maintainer will need to approve the last

>> patch once it's final.)

>

> As far as I'm concerned that would be the attached third patch:

> "Don't maintain a warning spec for 'UNKNOWN_LOCATION'/'BUILTINS_LOCATION'

> [PR101574]".  OK to push?

>

>

> Grüße

>  Thomas

>

>

>>> PS.  Relevant code quoted for reference, in case that's useful:

>>>

>>>> --- /dev/null

>>>> +++ b/gcc/diagnostic-spec.h

>>>

>>>> [...]

>>>

>>>> +typedef location_t key_type_t;

>>>> +typedef int_hash <key_type_t, 0, UINT_MAX> xint_hash_t;

>>>> +typedef hash_map<xint_hash_t, nowarn_spec_t> xint_hash_map_t;

>>>> +

>>>> +/* A mapping from the location of an expression to the warning spec

>>>> +   set for it.  */

>>>> +extern GTY(()) xint_hash_map_t *nowarn_map;

>>>

>>>> [...]

>>>

>>>> --- /dev/null

>>>> +++ b/gcc/diagnostic-spec.c

>>>

>>>> [...]

>>>

>>>> +/* Map from location to its no-warning disposition.  */

>>>> +

>>>> +GTY(()) xint_hash_map_t *nowarn_map;

>>>> +

>>>> +/* Return the no-warning disposition for location LOC and option OPT

>>>> +   or for all/any otions by default.  */

>>>> +

>>>> +bool

>>>> +warning_suppressed_at (location_t loc, opt_code opt /* = all_warnings */)

>>>> +{

>>>> +  if (!nowarn_map)

>>>> +    return false;

>>>> +

>>>> +  if (const nowarn_spec_t* const pspec = nowarn_map->get (loc))

>>>> +    {

>>>> +      const nowarn_spec_t optspec (opt);

>>>> +      return *pspec & optspec;

>>>> +    }

>>>> +

>>>> +  return false;

>>>> +}

>>>> +

>>>> + /* Change the supression of warnings at location LOC.

>>>> +    OPT controls which warnings are affected.

>>>> +    The wildcard OPT of -1 controls all warnings.

>>>> +    If SUPP is true (the default), enable the suppression of the warnings.

>>>> +    If SUPP is false, disable the suppression of the warnings.  */

>>>> +

>>>> +bool

>>>> +suppress_warning_at (location_t loc, opt_code opt /* = all_warnings */,

>>>> +                  bool supp /* = true */)

>>>> +{

>>>> +  const nowarn_spec_t optspec (supp ? opt : opt_code ());

>>>> +

>>>> +  if (nowarn_spec_t *pspec = nowarn_map ? nowarn_map->get (loc) : NULL)

>>>> +    {

>>>> +      if (supp)

>>>> +     {

>>>> +       *pspec |= optspec;

>>>> +       return true;

>>>> +     }

>>>> +

>>>> +      *pspec &= optspec;

>>>> +      if (*pspec)

>>>> +     return true;

>>>> +

>>>> +      nowarn_map->remove (loc);

>>>> +      return false;

>>>> +    }

>>>> +

>>>> +  if (!supp || opt == no_warning)

>>>> +    return false;

>>>> +

>>>> +  if (!nowarn_map)

>>>> +    nowarn_map = xint_hash_map_t::create_ggc (32);

>>>> +

>>>> +  nowarn_map->put (loc, optspec);

>>>> +  return true;

>>>> +}

>>>> +

>>>> +/* Copy the no-warning disposition from one location to another.  */

>>>> +

>>>> +void

>>>> +copy_warning (location_t to, location_t from)

>>>> +{

>>>> +  if (!nowarn_map)

>>>> +    return;

>>>> +

>>>> +  if (nowarn_spec_t *pspec = nowarn_map->get (from))

>>>> +    nowarn_map->put (to, *pspec);

>>>> +  else

>>>> +    nowarn_map->remove (to);

>>>> +}

>>>

>>>> --- /dev/null

>>>> +++ b/gcc/warning-control.cc

>>>

>>>> [...]

>>>

>>>> +/* Return the no-warning bit for EXPR.  */

>>>> +

>>>> +static inline bool

>>>> +get_no_warning_bit (const_tree expr)

>>>> +{

>>>> +  return expr->base.nowarning_flag;

>>>> +}

>>>> +

>>>> +/* Return the no-warning bit for statement STMT.  */

>>>> +

>>>> +static inline bool

>>>> +get_no_warning_bit (const gimple *stmt)

>>>> +{

>>>> +  return stmt->no_warning;

>>>> +}

>>>> +

>>>> +/* Set the no-warning bit for EXPR to VALUE.  */

>>>> +

>>>> +static inline void

>>>> +set_no_warning_bit (tree expr, bool value)

>>>> +{

>>>> +  expr->base.nowarning_flag = value;

>>>> +}

>>>> +

>>>> +/* Set the no-warning bit for statement STMT to VALUE.  */

>>>> +

>>>> +static inline void

>>>> +set_no_warning_bit (gimple *stmt, bool value)

>>>> +{

>>>> +  stmt->no_warning = value;

>>>> +}

>>>> +

>>>> +/* Return EXPR location or zero.  */

>>>> +

>>>> +static inline key_type_t

>>>> +convert_to_key (const_tree expr)

>>>> +{

>>>> +  if (DECL_P (expr))

>>>> +    return DECL_SOURCE_LOCATION (expr);

>>>> +  if (EXPR_P (expr))

>>>> +    return EXPR_LOCATION (expr);

>>>> +  return 0;

>>>> +}

>>>> +

>>>> +/* Return STMT location (may be zero).  */

>>>> +

>>>> +static inline key_type_t

>>>> +convert_to_key (const gimple *stmt)

>>>> +{

>>>> +  return gimple_location (stmt);

>>>> +}

>>>> +

>>>> +/* Return the no-warning bitmap for decl/expression EXPR.  */

>>>> +

>>>> +static nowarn_spec_t *

>>>> +get_nowarn_spec (const_tree expr)

>>>> +{

>>>> +  const key_type_t key = convert_to_key (expr);

>>>> +

>>>> +  if (!get_no_warning_bit (expr) || !key)

>>>> +    return NULL;

>>>> +

>>>> +  return nowarn_map ? nowarn_map->get (key) : NULL;

>>>> +}

>>>> +

>>>> +/* Return the no-warning bitmap for stateemt STMT.  */

>>>> +

>>>> +static nowarn_spec_t *

>>>> +get_nowarn_spec (const gimple *stmt)

>>>> +{

>>>> +  const key_type_t key = convert_to_key (stmt);

>>>> +

>>>> +  if (!get_no_warning_bit (stmt))

>>>> +    return NULL;

>>>> +

>>>> +  return nowarn_map ? nowarn_map->get (key) : NULL;

>>>> +}

>>>> +

>>>> +/* Return true if warning OPT is suppressed for decl/expression EXPR.

>>>> +   By default tests the disposition for any warning.  */

>>>> +

>>>> +bool

>>>> +warning_suppressed_p (const_tree expr, opt_code opt /* = all_warnings */)

>>>> +{

>>>> +  const nowarn_spec_t *spec = get_nowarn_spec (expr);

>>>> +

>>>> +  if (!spec)

>>>> +    return get_no_warning_bit (expr);

>>>> +

>>>> +  const nowarn_spec_t optspec (opt);

>>>> +  bool dis = *spec & optspec;

>>>> +  gcc_assert (get_no_warning_bit (expr) || !dis);

>>>> +  return dis;

>>>> +}

>>>> +

>>>> +/* Return true if warning OPT is suppressed for statement STMT.

>>>> +   By default tests the disposition for any warning.  */

>>>> +

>>>> +bool

>>>> +warning_suppressed_p (const gimple *stmt, opt_code opt /* = all_warnings */)

>>>> +{

>>>> +  const nowarn_spec_t *spec = get_nowarn_spec (stmt);

>>>> +

>>>> +  if (!spec)

>>>> +    /* Fall back on the single no-warning bit.  */

>>>> +    return get_no_warning_bit (stmt);

>>>> +

>>>> +  const nowarn_spec_t optspec (opt);

>>>> +  bool dis = *spec & optspec;

>>>> +  gcc_assert (get_no_warning_bit (stmt) || !dis);

>>>> +  return dis;

>>>> +}

>>>> +

>>>> +/* Enable, or by default disable, a warning for the expression.

>>>> +   The wildcard OPT of -1 controls all warnings.  */

>>>> +

>>>> +void

>>>> +suppress_warning (tree expr, opt_code opt /* = all_warnings */,

>>>> +               bool supp /* = true */)

>>>> +{

>>>> +  if (opt == no_warning)

>>>> +    return;

>>>> +

>>>> +  const key_type_t key = convert_to_key (expr);

>>>> +

>>>> +  supp = suppress_warning_at (key, opt, supp) || supp;

>>>> +  set_no_warning_bit (expr, supp);

>>>> +}

>>>> +

>>>> +/* Enable, or by default disable, a warning for the statement STMT.

>>>> +   The wildcard OPT of -1 controls all warnings.  */

>>>> +

>>>> +void

>>>> +suppress_warning (gimple *stmt, opt_code opt /* = all_warnings */,

>>>> +               bool supp /* = true */)

>>>> +{

>>>> +  if (opt == no_warning)

>>>> +    return;

>>>> +

>>>> +  const key_type_t key = convert_to_key (stmt);

>>>> +

>>>> +  supp = suppress_warning_at (key, opt, supp) || supp;

>>>> +  set_no_warning_bit (stmt, supp);

>>>> +}

>>>> +

>>>> +/* Copy the warning disposition mapping between an expression and/or

>>>> +   a statement.  */

>>>> +

>>>> +template <class ToType, class FromType>

>>>> +void copy_warning (ToType to, FromType from)

>>>> +{

>>>> +  const key_type_t to_key = convert_to_key (to);

>>>> +

>>>> +  if (nowarn_spec_t *from_map = get_nowarn_spec (from))

>>>> +    {

>>>> +      /* If there's an entry in the map the no-warning bit must be set.  */

>>>> +      gcc_assert (get_no_warning_bit (from));

>>>> +

>>>> +      if (!nowarn_map)

>>>> +     nowarn_map = xint_hash_map_t::create_ggc (32);

>>>> +

>>>> +      nowarn_map->put (to_key, *from_map);

>>>> +      set_no_warning_bit (to, true);

>>>> +    }

>>>> +  else

>>>> +    {

>>>> +      if (nowarn_map)

>>>> +     nowarn_map->remove (to_key);

>>>> +

>>>> +      /* The no-warning bit might be set even if there's no entry

>>>> +      in the map.  */

>>>> +      set_no_warning_bit (to, get_no_warning_bit (from));

>>>> +    }

>>>> +}

>>>> +

>>>> +/* Copy the warning disposition mapping from one expression to another.  */

>>>> +

>>>> +void

>>>> +copy_warning (tree to, const_tree from)

>>>> +{

>>>> +  copy_warning<tree, const_tree>(to, from);

>>>> +}

>>>> +

>>>> +/* Copy the warning disposition mapping from a statement to an expression.  */

>>>> +

>>>> +void

>>>> +copy_warning (tree to, const gimple *from)

>>>> +{

>>>> +  copy_warning<tree, const gimple *>(to, from);

>>>> +}

>>>> +

>>>> +/* Copy the warning disposition mapping from an expression to a statement.  */

>>>> +

>>>> +void

>>>> +copy_warning (gimple *to, const_tree from)

>>>> +{

>>>> +  copy_warning<gimple *, const_tree>(to, from);

>>>> +}

>>>> +

>>>> +/* Copy the warning disposition mapping from one statement to another.  */

>>>> +

>>>> +void

>>>> +copy_warning (gimple *to, const gimple *from)

>>>> +{

>>>> +  copy_warning<gimple *, const gimple *>(to, from);

>>>> +}



-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

Comments

Richard Biener via Gcc-patches Sept. 13, 2021, 2 p.m. | #1
On 9/10/2021 1:45 AM, Thomas Schwinge wrote:
>

> 0001-Simplify-gcc-diagnostic-spec.h-nowarn_map-setup.patch

>

>  From 095c16ead5d432726f2b6de5ce12fd367600076d Mon Sep 17 00:00:00 2001

> From: Thomas Schwinge <thomas@codesourcery.com>

> Date: Wed, 1 Sep 2021 16:48:55 +0200

> Subject: [PATCH 1/3] Simplify 'gcc/diagnostic-spec.h:nowarn_map' setup

>

> If we've just read something from the map, we can be sure that it exists.

>

> 	gcc/

> 	* warning-control.cc (copy_warning): Remove 'nowarn_map' setup.

> OK


>

> 0002-Clarify-key_type_t-to-location_t-as-used-for-gcc-dia.patch

>

>  From 23d9b93401349fca03efaef0fef0960933f4c316 Mon Sep 17 00:00:00 2001

> From: Thomas Schwinge <thomas@codesourcery.com>

> Date: Tue, 31 Aug 2021 22:01:23 +0200

> Subject: [PATCH 2/3] Clarify 'key_type_t' to 'location_t' as used for

>   'gcc/diagnostic-spec.h:nowarn_map'

>

> To make it obvious what exactly the key type is.  No change in behavior.

>

> 	gcc/

> 	* diagnostic-spec.h (typedef xint_hash_t): Use 'location_t' instead of...

> 	(typedef key_type_t): ... this.  Remove.

> 	(nowarn_map): Document.

> 	* diagnostic-spec.c (nowarn_map): Likewise.

> 	* warning-control.cc (convert_to_key): Evolve functions into...

> 	(get_location): ... these.  Adjust all users.

OK

>

> 0003-Don-t-maintain-a-warning-spec-for-UNKNOWN_LOCATION-B.patch

>

>  From 51c9a8ac2caa0432730c78d00989fd01f3ac6fe5 Mon Sep 17 00:00:00 2001

> From: Thomas Schwinge <thomas@codesourcery.com>

> Date: Mon, 30 Aug 2021 22:36:47 +0200

> Subject: [PATCH 3/3] Don't maintain a warning spec for

>   'UNKNOWN_LOCATION'/'BUILTINS_LOCATION' [PR101574]

> MIME-Version: 1.0

> Content-Type: text/plain; charset=UTF-8

> Content-Transfer-Encoding: 8bit

>

> This resolves PR101574 "gcc/sparseset.h:215:20: error: suggest parentheses

> around assignment used as truth value [-Werror=parentheses]", as (bogusly)

> reported at commit a61f6afbee370785cf091fe46e2e022748528307:

>

>      In file included from [...]/source-gcc/gcc/lra-lives.c:43:

>      [...]/source-gcc/gcc/lra-lives.c: In function ‘void make_hard_regno_dead(int)’:

>      [...]/source-gcc/gcc/sparseset.h:215:20: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]

>        215 |        && (((ITER) = sparseset_iter_elm (SPARSESET)) || 1);             \

>            |            ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

>      [...]/source-gcc/gcc/lra-lives.c:304:3: note: in expansion of macro ‘EXECUTE_IF_SET_IN_SPARSESET’

>        304 |   EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)

>            |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~

>

> 	gcc/

> 	PR bootstrap/101574

> 	* diagnostic-spec.c (warning_suppressed_at, copy_warning): Handle

> 	'RESERVED_LOCATION_P' locations.

> 	* warning-control.cc (get_nowarn_spec, suppress_warning)

> 	(copy_warning): Likewise.

OK.

Jeff

Patch

From 51c9a8ac2caa0432730c78d00989fd01f3ac6fe5 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Mon, 30 Aug 2021 22:36:47 +0200
Subject: [PATCH 3/3] Don't maintain a warning spec for
 'UNKNOWN_LOCATION'/'BUILTINS_LOCATION' [PR101574]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This resolves PR101574 "gcc/sparseset.h:215:20: error: suggest parentheses
around assignment used as truth value [-Werror=parentheses]", as (bogusly)
reported at commit a61f6afbee370785cf091fe46e2e022748528307:

    In file included from [...]/source-gcc/gcc/lra-lives.c:43:
    [...]/source-gcc/gcc/lra-lives.c: In function ‘void make_hard_regno_dead(int)’:
    [...]/source-gcc/gcc/sparseset.h:215:20: error: suggest parentheses around assignment used as truth value [-Werror=parentheses]
      215 |        && (((ITER) = sparseset_iter_elm (SPARSESET)) || 1);             \
          |            ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [...]/source-gcc/gcc/lra-lives.c:304:3: note: in expansion of macro ‘EXECUTE_IF_SET_IN_SPARSESET’
      304 |   EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
          |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~

	gcc/
	PR bootstrap/101574
	* diagnostic-spec.c (warning_suppressed_at, copy_warning): Handle
	'RESERVED_LOCATION_P' locations.
	* warning-control.cc (get_nowarn_spec, suppress_warning)
	(copy_warning): Likewise.
---
 gcc/diagnostic-spec.c  | 22 ++++++++++++++++---
 gcc/warning-control.cc | 48 +++++++++++++++++++++++++++---------------
 2 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c
index eac5a3317c8..85ffb725c02 100644
--- a/gcc/diagnostic-spec.c
+++ b/gcc/diagnostic-spec.c
@@ -115,6 +115,8 @@  GTY(()) xint_hash_map_t *nowarn_map;
 bool
 warning_suppressed_at (location_t loc, opt_code opt /* = all_warnings */)
 {
+  gcc_checking_assert (!RESERVED_LOCATION_P (loc));
+
   if (!nowarn_map)
     return false;
 
@@ -137,6 +139,8 @@  bool
 suppress_warning_at (location_t loc, opt_code opt /* = all_warnings */,
 		     bool supp /* = true */)
 {
+  gcc_checking_assert (!RESERVED_LOCATION_P (loc));
+
   const nowarn_spec_t optspec (supp ? opt : opt_code ());
 
   if (nowarn_spec_t *pspec = nowarn_map ? nowarn_map->get (loc) : NULL)
@@ -173,8 +177,20 @@  copy_warning (location_t to, location_t from)
   if (!nowarn_map)
     return;
 
-  if (nowarn_spec_t *pspec = nowarn_map->get (from))
-    nowarn_map->put (to, *pspec);
+  nowarn_spec_t *from_spec;
+  if (RESERVED_LOCATION_P (from))
+    from_spec = NULL;
+  else
+    from_spec = nowarn_map->get (from);
+  if (RESERVED_LOCATION_P (to))
+    /* We cannot set no-warning dispositions for 'to', so we have no chance but
+       lose those potentially set for 'from'.  */
+    ;
   else
-    nowarn_map->remove (to);
+    {
+      if (from_spec)
+	nowarn_map->put (to, *from_spec);
+      else
+	nowarn_map->remove (to);
+    }
 }
diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc
index 8d6c0828445..36a47ab6bae 100644
--- a/gcc/warning-control.cc
+++ b/gcc/warning-control.cc
@@ -89,7 +89,7 @@  get_nowarn_spec (const_tree expr)
 {
   const location_t loc = get_location (expr);
 
-  if (loc == UNKNOWN_LOCATION)
+  if (RESERVED_LOCATION_P (loc))
     return NULL;
 
   if (!get_no_warning_bit (expr))
@@ -105,6 +105,9 @@  get_nowarn_spec (const gimple *stmt)
 {
   const location_t loc = get_location (stmt);
 
+  if (RESERVED_LOCATION_P (loc))
+    return NULL;
+
   if (!get_no_warning_bit (stmt))
     return NULL;
 
@@ -158,7 +161,8 @@  suppress_warning (tree expr, opt_code opt /* = all_warnings */,
 
   const location_t loc = get_location (expr);
 
-  supp = suppress_warning_at (loc, opt, supp) || supp;
+  if (!RESERVED_LOCATION_P (loc))
+    supp = suppress_warning_at (loc, opt, supp) || supp;
   set_no_warning_bit (expr, supp);
 }
 
@@ -174,7 +178,8 @@  suppress_warning (gimple *stmt, opt_code opt /* = all_warnings */,
 
   const location_t loc = get_location (stmt);
 
-  supp = suppress_warning_at (loc, opt, supp) || supp;
+  if (!RESERVED_LOCATION_P (loc))
+    supp = suppress_warning_at (loc, opt, supp) || supp;
   set_no_warning_bit (stmt, supp);
 }
 
@@ -186,24 +191,33 @@  void copy_warning (ToType to, FromType from)
 {
   const location_t to_loc = get_location (to);
 
-  if (nowarn_spec_t *from_map = get_nowarn_spec (from))
-    {
-      /* If there's an entry in the map the no-warning bit must be set.  */
-      gcc_assert (get_no_warning_bit (from));
+  bool supp = get_no_warning_bit (from);
 
-      gcc_checking_assert (nowarn_map);
-      nowarn_map->put (to_loc, *from_map);
-      set_no_warning_bit (to, true);
-    }
+  nowarn_spec_t *from_spec = get_nowarn_spec (from);
+  if (RESERVED_LOCATION_P (to_loc))
+    /* We cannot set no-warning dispositions for 'to', so we have no chance but
+       lose those potentially set for 'from'.  */
+    ;
   else
     {
-      if (nowarn_map)
-	nowarn_map->remove (to_loc);
-
-      /* The no-warning bit might be set even if there's no entry
-	 in the map.  */
-      set_no_warning_bit (to, get_no_warning_bit (from));
+      if (from_spec)
+	{
+	  /* If there's an entry in the map the no-warning bit must be set.  */
+	  gcc_assert (supp);
+
+	  gcc_checking_assert (nowarn_map);
+	  nowarn_map->put (to_loc, *from_spec);
+	}
+      else
+	{
+	  if (nowarn_map)
+	    nowarn_map->remove (to_loc);
+	}
     }
+
+  /* The no-warning bit might be set even if the map has not been consulted, or
+     otherwise if there's no entry in the map.  */
+  set_no_warning_bit (to, supp);
 }
 
 /* Copy the warning disposition mapping from one expression to another.  */
-- 
2.25.1