Summary: | Warning for mismatched declaration/definition with enum | ||
---|---|---|---|
Product: | gcc | Reporter: | Richard Henderson <rth> |
Component: | c | Assignee: | Marek Polacek <mpolacek> |
Status: | RESOLVED FIXED | ||
Severity: | enhancement | CC: | egallager, mpolacek, sjames |
Priority: | P3 | Keywords: | diagnostic |
Version: | 12.0 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2022-04-01 00:00:00 | |
Bug Depends on: | |||
Bug Blocks: | 87403 |
Description
Richard Henderson
2022-04-01 19:56:26 UTC
Confirmed. Maybe something like the attached patch would work (but needs a new option, maybe -Wenum-int-mismatch, possibly enabled by -Wall?). With it, the following test enum E { l = -1, z = 0, g = 1 }; int foo(void); enum E foo(void) { return z; } void bar(int); void bar(enum E); extern enum E arr[10]; extern int arr[10]; is diagnosed like this: 105131.c:3:8: warning: conflicting types for ‘foo’ due to enum/integer mismatch; have ‘enum E(void)’ 3 | enum E foo(void) { return z; } | ^~~ 105131.c:2:5: note: previous declaration of ‘foo’ with type ‘int(void)’ 2 | int foo(void); | ^~~ 105131.c:6:6: warning: conflicting types for ‘bar’ due to enum/integer mismatch; have ‘void(enum E)’ 6 | void bar(enum E); | ^~~ 105131.c:5:6: note: previous declaration of ‘bar’ with type ‘void(int)’ 5 | void bar(int); | ^~~ 105131.c:9:12: warning: conflicting types for ‘arr’ due to enum/integer mismatch; have ‘int[10]’ 9 | extern int arr[10]; | ^~~ 105131.c:8:15: note: previous declaration of ‘arr’ with type ‘enum E[10]’ 8 | extern enum E arr[10]; | ^~~ diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c701f07befe..60a0bb3ea36 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -1995,9 +1995,12 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, bool pedwarned = false; bool warned = false; + bool enum_and_int_p = false; auto_diagnostic_group d; - if (!comptypes (oldtype, newtype)) + int comptypes_result = comptypes_check_enum_int (oldtype, newtype, + &enum_and_int_p); + if (!comptypes_result) { if (TREE_CODE (olddecl) == FUNCTION_DECL && fndecl_built_in_p (olddecl, BUILT_IN_NORMAL) @@ -2139,6 +2142,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, return false; } } + else if (enum_and_int_p && TREE_CODE (newdecl) != TYPE_DECL) + { + location_t newloc = DECL_SOURCE_LOCATION (newdecl); + auto_diagnostic_group d; + warned = warning_at (newloc, 0, "conflicting types for %q+D due to " + "enum/integer mismatch; have %qT", newdecl, + newtype); + } /* Redeclaration of a type is a constraint violation (6.7.2.3p1), but silently ignore the redeclaration if either is in a system @@ -2148,7 +2159,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, if (TREE_CODE (newdecl) == TYPE_DECL) { bool types_different = false; - int comptypes_result; comptypes_result = comptypes_check_different_types (oldtype, newtype, &types_different); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index c70f0ba5ab6..2bcb9662620 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -685,6 +685,7 @@ extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); extern int comptypes_check_different_types (tree, tree, bool *); +extern int comptypes_check_enum_int (tree, tree, bool *); extern bool c_vla_type_p (const_tree); extern bool c_mark_addressable (tree, bool = false); extern void c_incomplete_type_error (location_t, const_tree, const_tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 6c4af5e4cde..b6a45fd9836 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1055,7 +1055,7 @@ comptypes (tree type1, tree type2) /* Like comptypes, but if it returns non-zero because enum and int are compatible, it sets *ENUM_AND_INT_P to true. */ -static int +int comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) { const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base; The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:7da9a089608b0ca09683332ce014fb6184842724 commit r13-627-g7da9a089608b0ca09683332ce014fb6184842724 Author: Marek Polacek <polacek@redhat.com> Date: Fri Apr 1 16:55:58 2022 -0400 c: Implement new -Wenum-int-mismatch warning [PR105131] In C, an enumerated type is compatible with char, a signed integer type, or an unsigned integer type (6.7.2.2/5). Therefore this code compiles: enum E { l = -1, z = 0, g = 1 }; int foo(void); enum E foo(void) { return z; } if the underlying type of 'enum E' is 'int' (if not, we emit an error). This is different for typedefs, where C11 permits typedefs to be redeclared to the same type, but not to compatible types. In C++, the code above is invalid. It seems desirable to emit a warning in the C case, because it is probably a mistake and definitely a portability error, given that the choice of the underlying type is implementation-defined. To that end, this patch implements a new -Wenum-int-mismatch warning. Conveniently, we already have comptypes_check_enum_int to detect such mismatches. This warning is enabled by either -Wall or -Wc++-compat. PR c/105131 gcc/c-family/ChangeLog: * c.opt (Wenum-int-mismatch): New. gcc/c/ChangeLog: * c-decl.cc (diagnose_mismatched_decls): Warn about enum/integer type mismatches. * c-tree.h (comptypes_check_enum_int): Declare. * c-typeck.cc (comptypes): No longer static. gcc/ChangeLog: * doc/invoke.texi: Document -Wenum-int-mismatch. gcc/testsuite/ChangeLog: * gcc.dg/Wenum-int-mismatch-1.c: New test. * gcc.dg/Wenum-int-mismatch-2.c: New test. * gcc.dg/Wenum-int-mismatch-3.c: New test. * gcc.dg/Wenum-int-mismatch-4.c: New test. * gcc.dg/Wenum-int-mismatch-5.c: New test. Implemented in GCC 13. |