On 26 August 2017 at 04:15, Joseph Myers <jos...@codesourcery.com> wrote: > On Tue, 11 Jul 2017, Prathamesh Kulkarni wrote: > >> On 13 June 2017 at 01:47, Joseph Myers <jos...@codesourcery.com> wrote: >> > This is OK with one fix: >> > >> >> +C ObjC Var(warn_enum_conversion) Init(0) Warning LangEnabledBy(C >> >> Objc,Wall) >> > >> > I believe the LangEnabledBy arguments are case-sensitive, so you need to >> > have ObjC not Objc there for it to work correctly. (*.opt parsing isn't >> > very good at detecting typos and giving errors rather than silently >> > ignoring things.) >> Hi, >> Sorry for the late response, I was on a vacation. >> The attached patch is rebased and bootstrap+tested on >> x86_64-unknown-linux-gnu. >> I have modified it slightly to not warn for enums with different names >> but having same value ranges. >> For eg: >> enum e1 { e1_1, e1_2 }; >> enum e2 { e2_1, e2_2 }; >> >> enum e1 x = e2_1; >> With this version, there would be no warning for the above assignment >> since both e1 and e2 have >> same value ranges. Is that OK ? > > I don't really think that's a good heuristic. I see no particular reason > to think that just because two enums have the same set of values, an > implicit conversion between them is actually deliberate - corresponding > values have the same semantics in some sense - rather than reflecting an > underlying confusion in the code. (You could have different levels of the > warning - and only warn in this case at a higher level - but I don't > really think that makes sense either for this particular warning.) Thanks for the suggestion, I have reverted this change in the attached patch. > >> The patch has following fallouts in the testsuite: >> >> a) libgomp: >> I initially assume it was a false positive because I thought enum >> gomp_schedule_type >> and enum omp_sched_t have same value-ranges but it looks like omp_sched_t >> has range [1, 4] while gomp_schedule_type has range [0, 4] with one >> extra element. >> Is the warning then correct for this case ? >> >> b) libgfortran: >> i) Implicit conversion from unit_mode to file_mode >> ii) Implicit conversion from unit_sign_s to unit_sign. >> I suppose the warning is OK for these cases since unit_mode, file_mode >> have different value-ranges and similarly for unit_sign_s, unit_sign ? > > If it's an implicit conversion between different enum types, the warning > is correct. The more important question for the review is: is it correct > to replace the implicit conversion by an explicit one? That is, for each > value in the source type, what enumerator of the destination type has the > same value, and do the semantics match in whatever way is required for the > code in question? Well, for instance unit_sign in libgfortran/io.h is defined as: typedef enum { SIGN_PROCDEFINED, SIGN_SUPPRESS, SIGN_PLUS, SIGN_UNSPECIFIED } unit_sign;
and unit_sign_s is defined: typedef enum { SIGN_S, SIGN_SS, SIGN_SP } unit_sign_s; Since the enum types are different, I assume warnings for implicit conversion from unit_sign_s to unit_sign would be correct ? And since unit_sign_s is a subset of unit_sign in terms of value-ranges, I assume replacing implicit by explicit conversion would be OK ? Thanks, Prathamesh > > Also note s/valeu/value/ in the documentation. > > -- > Joseph S. Myers > jos...@codesourcery.com
2017-10-01 Prathamesh Kulkarni <prathamesh.kulka...@linaro.org> * doc/invoke.texi: Document -Wenum-conversion. * c-family/c.opt (Wenum-conversion): New option. * c/c-typeck.c (convert_for_assignment): Handle Wenum-conversion. libgomp/ * icv.c (omp_set_schedule): Cast kind to enum gomp_schedule_type. (omp_get_schedule): Cast icv->run_sched_var to enum omp_sched_t before. libgfortran/ * io/transfer.c (current_mode): Cast FORM_UNSPECIFIED to file_mode. (formatted_transfer_scalar_read): Cast SIGN_S, SIGN_SS, SIGN_SP to unit_sign. (formatted_transfer_scalar_write): Likewise. testsuite/ * gcc.dg/Wenum-conversion.c: New test-case. diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 3435fe90cca..23a5d350bad 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -500,6 +500,10 @@ Wenum-compare C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning LangEnabledBy(C ObjC,Wall || Wc++-compat) Warn about comparison of different enum types. +Wenum-conversion +C ObjC Var(warn_enum_conversion) Init(0) Warning LangEnabledBy(C ObjC,Wall) +Warn about implicit conversion of enum types. + Werror C ObjC C++ ObjC++ ; Documented in common.opt diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 135dd9d665c..a46de0438e6 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -6341,6 +6341,20 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, } } + if (warn_enum_conversion) + { + tree checktype = origtype != NULL_TREE ? origtype : rhstype; + if (checktype != error_mark_node + && TREE_CODE (checktype) == ENUMERAL_TYPE + && TREE_CODE (type) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (type)) + { + gcc_rich_location loc (location); + warning_at_rich_loc (&loc, OPT_Wenum_conversion, "implicit conversion from" + " %qT to %qT", checktype, type); + } + } + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)) return rhs; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 64363e54a00..e6d2159d60d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -276,7 +276,8 @@ Objective-C and Objective-C++ Dialects}. -Wno-discarded-qualifiers -Wno-discarded-array-qualifiers @gol -Wno-div-by-zero -Wdouble-promotion @gol -Wduplicated-branches -Wduplicated-cond @gol --Wempty-body -Wenum-compare -Wno-endif-labels -Wexpansion-to-defined @gol +-Wempty-body -Wenum-compare -Wenum-conversion @gol +-Wno-endif-labels -Wexpansion-to-defined @gol -Werror -Werror=* -Wextra-semi -Wfatal-errors @gol -Wfloat-equal -Wformat -Wformat=2 @gol -Wno-format-contains-nul -Wno-format-extra-args @gol @@ -3831,6 +3832,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}. -Wcomment @gol -Wduplicate-decl-specifier @r{(C and Objective-C only)} @gol -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol +-Wenum-conversion @r{in C/ObjC;} @gol -Wformat @gol -Wint-in-bool-context @gol -Wimplicit @r{(C and Objective-C only)} @gol @@ -6084,6 +6086,12 @@ In C++ enumerated type mismatches in conditional expressions are also diagnosed and the warning is enabled by default. In C this warning is enabled by @option{-Wall}. +@item -Wenum-conversion @r{(C, Objective-C only)} +@opindex Wenum-conversion +@opindex Wno-enum-conversion +Warn when an enum value of a type is implicitly converted to an enum of +another type. This warning is enabled by @option{-Wall}. + @item -Wextra-semi @r{(C++, Objective-C++ only)} @opindex Wextra-semi @opindex Wno-extra-semi diff --git a/gcc/testsuite/gcc.dg/Wenum-conversion.c b/gcc/testsuite/gcc.dg/Wenum-conversion.c new file mode 100644 index 00000000000..86033399b7d --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wenum-conversion.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-Wenum-conversion" } */ + +enum X { x1, x2 }; +enum Y { y1, y2 }; + +enum X obj = y1; /* { dg-warning "implicit conversion from .enum Y. to .enum X." } */ +enum Y obj2 = y1; + +enum X obj3; +void foo() +{ + obj3 = y2; /* { dg-warning "implicit conversion from .enum Y. to .enum X." } */ +} + +void bar(enum X); +void f(void) +{ + bar (y1); /* { dg-warning "implicit conversion from .enum Y. to .enum X." } */ +} diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c index 529637061b1..3307d213bb7 100644 --- a/libgfortran/io/transfer.c +++ b/libgfortran/io/transfer.c @@ -196,7 +196,7 @@ current_mode (st_parameter_dt *dtp) { file_mode m; - m = FORM_UNSPECIFIED; + m = (file_mode) FORM_UNSPECIFIED; if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT) { @@ -1671,17 +1671,17 @@ formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind case FMT_S: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_S; + dtp->u.p.sign_status = (unit_sign) SIGN_S; break; case FMT_SS: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_SS; + dtp->u.p.sign_status = (unit_sign) SIGN_SS; break; case FMT_SP: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_SP; + dtp->u.p.sign_status = (unit_sign) SIGN_SP; break; case FMT_BN: @@ -2130,17 +2130,17 @@ formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kin case FMT_S: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_S; + dtp->u.p.sign_status = (unit_sign) SIGN_S; break; case FMT_SS: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_SS; + dtp->u.p.sign_status = (unit_sign) SIGN_SS; break; case FMT_SP: consume_data_flag = 0; - dtp->u.p.sign_status = SIGN_SP; + dtp->u.p.sign_status = (unit_sign) SIGN_SP; break; case FMT_BN: diff --git a/libgomp/icv.c b/libgomp/icv.c index 233d6dbe10e..71e1f677fd7 100644 --- a/libgomp/icv.c +++ b/libgomp/icv.c @@ -87,14 +87,14 @@ omp_set_schedule (omp_sched_t kind, int chunk_size) default: return; } - icv->run_sched_var = kind; + icv->run_sched_var = (enum gomp_schedule_type) kind; } void omp_get_schedule (omp_sched_t *kind, int *chunk_size) { struct gomp_task_icv *icv = gomp_icv (false); - *kind = icv->run_sched_var; + *kind = (enum omp_sched_t) icv->run_sched_var; *chunk_size = icv->run_sched_chunk_size; }