[C++] PR c++/90590 Suppress warning for enumeration value not handled in switch warning

Message ID CAOrE4X2ZKktGOw=LERUgu7sMkMQE04fwH8Lw7vNWu=1BKYpcFA@mail.gmail.com
State New
Headers show
Series
  • [C++] PR c++/90590 Suppress warning for enumeration value not handled in switch warning
Related show

Commit Message

Matthew Beliveau July 9, 2019, 3:18 p.m.
This patch suppresses the warning:  "enumeration value not handled in
switch", for enumerators that are defined in system headers and use
reserved names.

Comments

Marek Polacek July 9, 2019, 5:36 p.m. | #1
On Tue, Jul 09, 2019 at 11:18:53AM -0400, Matthew Beliveau wrote:
> index 00000000000..8aa65cf0afd

> --- /dev/null

> +++ gcc/testsuite/c-c++-common/pr90590-2.c

> @@ -0,0 +1,8 @@

> +#include "pr90590-2.h"

> +

> +void

> +fn ()

> +{

> +  switch (c.b) // { dg-bogus "enumeration value" }

> +    ;

> +}


I suppose this test should also have
// PR c++/90590
// { dg-options -Wswitch }
because without -Wswitch the warning wouldn't trigger in any case.

Marek
Jason Merrill July 9, 2019, 9:21 p.m. | #2
On 7/9/19 11:18 AM, Matthew Beliveau wrote:
> This patch suppresses the warning:  "enumeration value not handled in

> switch", for enumerators that are defined in system headers and use

> reserved names.


> +      if (decl == NULL_TREE)

> +	decl = lookup_name (TREE_PURPOSE (chain));


This seems likely to find an unrelated declaration.  If we have a name 
without a decl, I think it would be better to just look at that name 
rather than try to find the corresponding decl.  For location, we can 
use the location of the type.

Jason
Matthew Beliveau July 12, 2019, 6:34 p.m. | #3
Hi,
This should fix the concerns you had! Now the function only gets the
location from the type, and then only look for the name if the type's
location is in the header.

On Tue, Jul 9, 2019 at 5:21 PM Jason Merrill <jason@redhat.com> wrote:
>

> On 7/9/19 11:18 AM, Matthew Beliveau wrote:

> > This patch suppresses the warning:  "enumeration value not handled in

> > switch", for enumerators that are defined in system headers and use

> > reserved names.

>

> > +      if (decl == NULL_TREE)

> > +     decl = lookup_name (TREE_PURPOSE (chain));

>

> This seems likely to find an unrelated declaration.  If we have a name

> without a decl, I think it would be better to just look at that name

> rather than try to find the corresponding decl.  For location, we can

> use the location of the type.

>

> Jason
Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-07-12  Matthew Beliveau  <mbelivea@redhat.com>

	PR c++/90590
	* c-warn.c (c_do_switch_warnings): Suppress warning for enumerators
	with reserved names that are in a system header.

	* c-c++-common/pr90590-1.c: New test.
	* c-c++-common/pr90590-1.h: New test.
	* c-c++-common/pr90590-2.c: New test.
	* c-c++-common/pr90590-2.h: New test.

diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
index b5d09e761d7..e120ad96f4b 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "gimplify.h"
 #include "c-family/c-indentation.h"
+#include "c-family/c-spellcheck.h"
 #include "calls.h"
 #include "stor-layout.h"
 
@@ -1628,6 +1629,16 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
       if (cond && tree_int_cst_compare (cond, value))
 	continue;
 
+      /* If the enumerator is defined in a system header and uses a reserved
+	 name, then we continue to avoid throwing a warning.  */
+      location_t loc = DECL_SOURCE_LOCATION
+	    (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));
+      if (in_system_header_at (loc)
+	  && name_reserved_for_implementation_p
+	      (IDENTIFIER_POINTER (TREE_PURPOSE (chain))))
+	continue;
+
+
       /* If there is a default_node, the only relevant option is
 	 Wswitch-enum.  Otherwise, if both are enabled then we prefer
 	 to warn using -Wswitch because -Wswitch is enabled by -Wall
diff --git gcc/testsuite/c-c++-common/pr90590-1.c gcc/testsuite/c-c++-common/pr90590-1.c
new file mode 100644
index 00000000000..4e11debb7fa
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.c
@@ -0,0 +1,15 @@
+// PR c++/90590
+// { dg-options -Wswitch }
+#include "pr90590-1.h"
+
+void
+g ()
+{
+  enum E e = _A;
+  switch (e) // { dg-bogus "enumeration value '_C' not handled in switch" }
+    {
+    case _A:
+    case _B:
+      break;
+    }
+}
diff --git gcc/testsuite/c-c++-common/pr90590-1.h gcc/testsuite/c-c++-common/pr90590-1.h
new file mode 100644
index 00000000000..22f1a7d5d52
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.h
@@ -0,0 +1,2 @@
+#pragma GCC system_header
+enum E { _A, _B, _C };
diff --git gcc/testsuite/c-c++-common/pr90590-2.c gcc/testsuite/c-c++-common/pr90590-2.c
new file mode 100644
index 00000000000..23da97f9d74
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.c
@@ -0,0 +1,11 @@
+// PR c++/90590
+// { dg-options -Wswitch }
+
+#include "pr90590-2.h"
+
+void
+fn ()
+{
+  switch (c.b) // { dg-bogus "enumeration value" }
+    ;
+}
diff --git gcc/testsuite/c-c++-common/pr90590-2.h gcc/testsuite/c-c++-common/pr90590-2.h
new file mode 100644
index 00000000000..e4f8635576f
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.h
@@ -0,0 +1,4 @@
+#pragma GCC system_header
+struct {
+  enum { _A } b;
+} c;
Marek Polacek July 12, 2019, 6:38 p.m. | #4
On Fri, Jul 12, 2019 at 02:34:37PM -0400, Matthew Beliveau wrote:
> @@ -1628,6 +1629,16 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,

>        if (cond && tree_int_cst_compare (cond, value))

>  	continue;

>  

> +      /* If the enumerator is defined in a system header and uses a reserved

> +	 name, then we continue to avoid throwing a warning.  */

> +      location_t loc = DECL_SOURCE_LOCATION

> +	    (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));


As I mentioned before, I wonder if we can get away without the
TYPE_MAIN_VARIANT here.

> +      if (in_system_header_at (loc)

> +	  && name_reserved_for_implementation_p

> +	      (IDENTIFIER_POINTER (TREE_PURPOSE (chain))))

> +	continue;

> +

> +


Please drop one newline here.

Marek
Marek Polacek July 12, 2019, 10:49 p.m. | #5
On Fri, Jul 12, 2019 at 02:38:59PM -0400, Marek Polacek wrote:
> On Fri, Jul 12, 2019 at 02:34:37PM -0400, Matthew Beliveau wrote:

> > @@ -1628,6 +1629,16 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,

> >        if (cond && tree_int_cst_compare (cond, value))

> >  	continue;

> >  

> > +      /* If the enumerator is defined in a system header and uses a reserved

> > +	 name, then we continue to avoid throwing a warning.  */

> > +      location_t loc = DECL_SOURCE_LOCATION

> > +	    (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));

> 

> As I mentioned before, I wonder if we can get away without the

> TYPE_MAIN_VARIANT here.


Ah, without TYPE_MAIN_VARIANT there's this ICEs:

/opt/notnfs/polacek/gcc/libstdc++-v3/src/c++11/debug.cc: In function ‘void {anonymous}::print_field({anonymous}::PrintContext&, const _Parameter&, const char*)’:
/opt/notnfs/polacek/gcc/libstdc++-v3/src/c++11/debug.cc:791:5: internal compiler error: Segmentation fault
  791 |     }
      |     ^
0xf31def crash_signal
        /opt/notnfs/polacek/gcc/gcc/toplev.c:326
0xaaa579 contains_struct_check(tree_node*, tree_node_structure_enum, char const*, int, char const*)
        /opt/notnfs/polacek/gcc/gcc/tree.h:3330
0xaaa579 c_do_switch_warnings(splay_tree_s*, unsigned int, tree_node*, tree_node*, bool)
        /opt/notnfs/polacek/gcc/gcc/c-family/c-warn.c:1634
0x8ab61f pop_switch()
        /opt/notnfs/polacek/gcc/gcc/cp/decl.c:3567
0x9e0af4 finish_switch_stmt(tree_node*)
        /opt/notnfs/polacek/gcc/gcc/cp/semantics.c:1229
0x95764d cp_parser_selection_statement
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11964
0x95764d cp_parser_statement
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11186
0x958770 cp_parser_statement_seq_opt
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11667
0x958847 cp_parser_compound_statement
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11621
0x971990 cp_parser_function_body
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:22651
0x971990 cp_parser_ctor_initializer_opt_and_function_body
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:22702
0x972216 cp_parser_function_definition_after_declarator
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:28016
0x972fae cp_parser_function_definition_from_specifiers_and_declarator
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:27932
0x972fae cp_parser_init_declarator
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:20288
0x954ecf cp_parser_simple_declaration
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13546
0x9798a2 cp_parser_declaration
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13243
0x97a46c cp_parser_declaration_seq_opt
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13119
0x97a46c cp_parser_namespace_body
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:19335
0x97a46c cp_parser_namespace_definition
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:19313
0x9799b3 cp_parser_declaration
        /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13223
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

So seems like we need it after all.  Sorry about that.

Marek
Matthew Beliveau July 15, 2019, 1:47 p.m. | #6
Okay I kept the TYPE_MAIN_VARIANT and dropped the accidental new line!
Hopefully this should be fine!

On Fri, Jul 12, 2019 at 6:49 PM Marek Polacek <polacek@redhat.com> wrote:
>

> On Fri, Jul 12, 2019 at 02:38:59PM -0400, Marek Polacek wrote:

> > On Fri, Jul 12, 2019 at 02:34:37PM -0400, Matthew Beliveau wrote:

> > > @@ -1628,6 +1629,16 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,

> > >        if (cond && tree_int_cst_compare (cond, value))

> > >     continue;

> > >

> > > +      /* If the enumerator is defined in a system header and uses a reserved

> > > +    name, then we continue to avoid throwing a warning.  */

> > > +      location_t loc = DECL_SOURCE_LOCATION

> > > +       (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));

> >

> > As I mentioned before, I wonder if we can get away without the

> > TYPE_MAIN_VARIANT here.

>

> Ah, without TYPE_MAIN_VARIANT there's this ICEs:

>

> /opt/notnfs/polacek/gcc/libstdc++-v3/src/c++11/debug.cc: In function ‘void {anonymous}::print_field({anonymous}::PrintContext&, const _Parameter&, const char*)’:

> /opt/notnfs/polacek/gcc/libstdc++-v3/src/c++11/debug.cc:791:5: internal compiler error: Segmentation fault

>   791 |     }

>       |     ^

> 0xf31def crash_signal

>         /opt/notnfs/polacek/gcc/gcc/toplev.c:326

> 0xaaa579 contains_struct_check(tree_node*, tree_node_structure_enum, char const*, int, char const*)

>         /opt/notnfs/polacek/gcc/gcc/tree.h:3330

> 0xaaa579 c_do_switch_warnings(splay_tree_s*, unsigned int, tree_node*, tree_node*, bool)

>         /opt/notnfs/polacek/gcc/gcc/c-family/c-warn.c:1634

> 0x8ab61f pop_switch()

>         /opt/notnfs/polacek/gcc/gcc/cp/decl.c:3567

> 0x9e0af4 finish_switch_stmt(tree_node*)

>         /opt/notnfs/polacek/gcc/gcc/cp/semantics.c:1229

> 0x95764d cp_parser_selection_statement

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11964

> 0x95764d cp_parser_statement

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11186

> 0x958770 cp_parser_statement_seq_opt

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11667

> 0x958847 cp_parser_compound_statement

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:11621

> 0x971990 cp_parser_function_body

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:22651

> 0x971990 cp_parser_ctor_initializer_opt_and_function_body

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:22702

> 0x972216 cp_parser_function_definition_after_declarator

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:28016

> 0x972fae cp_parser_function_definition_from_specifiers_and_declarator

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:27932

> 0x972fae cp_parser_init_declarator

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:20288

> 0x954ecf cp_parser_simple_declaration

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13546

> 0x9798a2 cp_parser_declaration

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13243

> 0x97a46c cp_parser_declaration_seq_opt

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13119

> 0x97a46c cp_parser_namespace_body

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:19335

> 0x97a46c cp_parser_namespace_definition

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:19313

> 0x9799b3 cp_parser_declaration

>         /opt/notnfs/polacek/gcc/gcc/cp/parser.c:13223

> Please submit a full bug report,

> with preprocessed source if appropriate.

> Please include the complete backtrace with any bug report.

> See <https://gcc.gnu.org/bugs/> for instructions.

>

> So seems like we need it after all.  Sorry about that.

>

> Marek
Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-07-12  Matthew Beliveau  <mbelivea@redhat.com>

	PR c++/90590
	* c-warn.c (c_do_switch_warnings): Suppress warning for enumerators
	with reserved names that are in a system header.

	* c-c++-common/pr90590-1.c: New test.
	* c-c++-common/pr90590-1.h: New test.
	* c-c++-common/pr90590-2.c: New test.
	* c-c++-common/pr90590-2.h: New test.

diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
index b5d09e761d7..51c54a283e5 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "gimplify.h"
 #include "c-family/c-indentation.h"
+#include "c-family/c-spellcheck.h"
 #include "calls.h"
 #include "stor-layout.h"
 
@@ -1628,6 +1629,15 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
       if (cond && tree_int_cst_compare (cond, value))
 	continue;
 
+      /* If the enumerator is defined in a system header and uses a reserved
+	 name, then we continue to avoid throwing a warning.  */
+      location_t loc = DECL_SOURCE_LOCATION
+	    (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));
+      if (in_system_header_at (loc)
+	  && name_reserved_for_implementation_p
+	      (IDENTIFIER_POINTER (TREE_PURPOSE (chain))))
+	continue;
+
       /* If there is a default_node, the only relevant option is
 	 Wswitch-enum.  Otherwise, if both are enabled then we prefer
 	 to warn using -Wswitch because -Wswitch is enabled by -Wall
diff --git gcc/testsuite/c-c++-common/pr90590-1.c gcc/testsuite/c-c++-common/pr90590-1.c
new file mode 100644
index 00000000000..4e11debb7fa
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.c
@@ -0,0 +1,15 @@
+// PR c++/90590
+// { dg-options -Wswitch }
+#include "pr90590-1.h"
+
+void
+g ()
+{
+  enum E e = _A;
+  switch (e) // { dg-bogus "enumeration value '_C' not handled in switch" }
+    {
+    case _A:
+    case _B:
+      break;
+    }
+}
diff --git gcc/testsuite/c-c++-common/pr90590-1.h gcc/testsuite/c-c++-common/pr90590-1.h
new file mode 100644
index 00000000000..22f1a7d5d52
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.h
@@ -0,0 +1,2 @@
+#pragma GCC system_header
+enum E { _A, _B, _C };
diff --git gcc/testsuite/c-c++-common/pr90590-2.c gcc/testsuite/c-c++-common/pr90590-2.c
new file mode 100644
index 00000000000..23da97f9d74
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.c
@@ -0,0 +1,11 @@
+// PR c++/90590
+// { dg-options -Wswitch }
+
+#include "pr90590-2.h"
+
+void
+fn ()
+{
+  switch (c.b) // { dg-bogus "enumeration value" }
+    ;
+}
diff --git gcc/testsuite/c-c++-common/pr90590-2.h gcc/testsuite/c-c++-common/pr90590-2.h
new file mode 100644
index 00000000000..e4f8635576f
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.h
@@ -0,0 +1,4 @@
+#pragma GCC system_header
+struct {
+  enum { _A } b;
+} c;
Marek Polacek July 16, 2019, 12:39 p.m. | #7
On Mon, Jul 15, 2019 at 09:47:26AM -0400, Matthew Beliveau wrote:
> Okay I kept the TYPE_MAIN_VARIANT and dropped the accidental new line!

> Hopefully this should be fine!


CCing Joseph as this is c-family/ stuff.

> Bootstrapped/regtested on x86_64-linux, ok for trunk?

> 

> 2019-07-12  Matthew Beliveau  <mbelivea@redhat.com>

> 

> 	PR c++/90590

> 	* c-warn.c (c_do_switch_warnings): Suppress warning for enumerators

> 	with reserved names that are in a system header.

> 

> 	* c-c++-common/pr90590-1.c: New test.

> 	* c-c++-common/pr90590-1.h: New test.

> 	* c-c++-common/pr90590-2.c: New test.

> 	* c-c++-common/pr90590-2.h: New test.

> 

> diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c

> index b5d09e761d7..51c54a283e5 100644

> --- gcc/c-family/c-warn.c

> +++ gcc/c-family/c-warn.c

> @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see

>  #include "gcc-rich-location.h"

>  #include "gimplify.h"

>  #include "c-family/c-indentation.h"

> +#include "c-family/c-spellcheck.h"

>  #include "calls.h"

>  #include "stor-layout.h"

>  

> @@ -1628,6 +1629,15 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,

>        if (cond && tree_int_cst_compare (cond, value))

>  	continue;

>  

> +      /* If the enumerator is defined in a system header and uses a reserved

> +	 name, then we continue to avoid throwing a warning.  */

> +      location_t loc = DECL_SOURCE_LOCATION

> +	    (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)));

> +      if (in_system_header_at (loc)

> +	  && name_reserved_for_implementation_p

> +	      (IDENTIFIER_POINTER (TREE_PURPOSE (chain))))

> +	continue;

> +

>        /* If there is a default_node, the only relevant option is

>  	 Wswitch-enum.  Otherwise, if both are enabled then we prefer

>  	 to warn using -Wswitch because -Wswitch is enabled by -Wall

> diff --git gcc/testsuite/c-c++-common/pr90590-1.c gcc/testsuite/c-c++-common/pr90590-1.c

> new file mode 100644

> index 00000000000..4e11debb7fa

> --- /dev/null

> +++ gcc/testsuite/c-c++-common/pr90590-1.c

> @@ -0,0 +1,15 @@

> +// PR c++/90590

> +// { dg-options -Wswitch }

> +#include "pr90590-1.h"

> +

> +void

> +g ()

> +{

> +  enum E e = _A;

> +  switch (e) // { dg-bogus "enumeration value '_C' not handled in switch" }

> +    {

> +    case _A:

> +    case _B:

> +      break;

> +    }

> +}

> diff --git gcc/testsuite/c-c++-common/pr90590-1.h gcc/testsuite/c-c++-common/pr90590-1.h

> new file mode 100644

> index 00000000000..22f1a7d5d52

> --- /dev/null

> +++ gcc/testsuite/c-c++-common/pr90590-1.h

> @@ -0,0 +1,2 @@

> +#pragma GCC system_header

> +enum E { _A, _B, _C };

> diff --git gcc/testsuite/c-c++-common/pr90590-2.c gcc/testsuite/c-c++-common/pr90590-2.c

> new file mode 100644

> index 00000000000..23da97f9d74

> --- /dev/null

> +++ gcc/testsuite/c-c++-common/pr90590-2.c

> @@ -0,0 +1,11 @@

> +// PR c++/90590

> +// { dg-options -Wswitch }

> +

> +#include "pr90590-2.h"

> +

> +void

> +fn ()

> +{

> +  switch (c.b) // { dg-bogus "enumeration value" }

> +    ;

> +}

> diff --git gcc/testsuite/c-c++-common/pr90590-2.h gcc/testsuite/c-c++-common/pr90590-2.h

> new file mode 100644

> index 00000000000..e4f8635576f

> --- /dev/null

> +++ gcc/testsuite/c-c++-common/pr90590-2.h

> @@ -0,0 +1,4 @@

> +#pragma GCC system_header

> +struct {

> +  enum { _A } b;

> +} c;



Marek

Patch

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-07-08  Matthew Beliveau  <mbelivea@redhat.com>
	
PR c++/90590
	* c-warn.c (c_do_switch_warnings): Suppress warning for enumerators
	with reserved names that are in a system header.

	* c-c++-common/pr90590-1.c: New test.
	* c-c++-common/pr90590-1.h: New test.
	* c-c++-common/pr90590-2.c: New test.
	* c-c++-common/pr90590-2.h: New test.

diff --git gcc/c-family/c-warn.c gcc/c-family/c-warn.c
index b5d09e761d7..56ad23dd29c 100644
--- gcc/c-family/c-warn.c
+++ gcc/c-family/c-warn.c
@@ -34,6 +34,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "gcc-rich-location.h"
 #include "gimplify.h"
 #include "c-family/c-indentation.h"
+#include "c-family/c-spellcheck.h"
 #include "calls.h"
 #include "stor-layout.h"
 
@@ -1592,8 +1593,12 @@  c_do_switch_warnings (splay_tree cases, location_t switch_location,
   for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
     {
       tree value = TREE_VALUE (chain);
+      tree decl = NULL_TREE;
       if (TREE_CODE (value) == CONST_DECL)
-	value = DECL_INITIAL (value);
+	{
+	  decl = value;
+	  value = DECL_INITIAL (value);
+	}
       node = splay_tree_lookup (cases, (splay_tree_key) value);
       if (node)
 	{
@@ -1628,6 +1633,19 @@  c_do_switch_warnings (splay_tree cases, location_t switch_location,
       if (cond && tree_int_cst_compare (cond, value))
 	continue;
 
+      /* If the enumerator is defined in a system header and uses a reserved
+	 name, then we continue to avoid throwing a warning.  */
+      if (decl == NULL_TREE)
+	decl = lookup_name (TREE_PURPOSE (chain));
+      if (decl && TREE_CODE (decl) == CONST_DECL)
+	{
+	  const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+	  location_t loc = DECL_SOURCE_LOCATION (decl);
+	  if (in_system_header_at (loc)
+	      && name_reserved_for_implementation_p (name))
+	    continue;
+	}
+
       /* If there is a default_node, the only relevant option is
 	 Wswitch-enum.  Otherwise, if both are enabled then we prefer
 	 to warn using -Wswitch because -Wswitch is enabled by -Wall
diff --git gcc/testsuite/c-c++-common/pr90590-1.c gcc/testsuite/c-c++-common/pr90590-1.c
new file mode 100644
index 00000000000..4997a3082d5
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.c
@@ -0,0 +1,15 @@ 
+// PR c++/90590
+// { dg-options -Wswitch }
+#include "pr90590-1.h"
+
+void
+g ()
+{
+  enum E e = _A;
+  switch (e) // { dg-bogus "enumeration value '_C' not handled in switch" }
+    {
+    case _A:
+    case _B:
+      break;
+    }
+}
diff --git gcc/testsuite/c-c++-common/pr90590-1.h gcc/testsuite/c-c++-common/pr90590-1.h
new file mode 100644
index 00000000000..22f1a7d5d52
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-1.h
@@ -0,0 +1,2 @@ 
+#pragma GCC system_header
+enum E { _A, _B, _C };
diff --git gcc/testsuite/c-c++-common/pr90590-2.c gcc/testsuite/c-c++-common/pr90590-2.c
new file mode 100644
index 00000000000..8aa65cf0afd
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.c
@@ -0,0 +1,8 @@ 
+#include "pr90590-2.h"
+
+void
+fn ()
+{
+  switch (c.b) // { dg-bogus "enumeration value" }
+    ;
+}
diff --git gcc/testsuite/c-c++-common/pr90590-2.h gcc/testsuite/c-c++-common/pr90590-2.h
new file mode 100644
index 00000000000..e4f8635576f
--- /dev/null
+++ gcc/testsuite/c-c++-common/pr90590-2.h
@@ -0,0 +1,4 @@ 
+#pragma GCC system_header
+struct {
+  enum { _A } b;
+} c;