All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kamil Dudka <kdudka@redhat.com>
To: Josh Triplett <josh@joshtriplett.org>,
	Stephen Hemminger <shemminger@vyatta.com>
Cc: linux-sparse@vger.kernel.org
Subject: Re: [PATCH] add warnings enum-to-int and int-to-enum
Date: Wed, 2 Sep 2009 13:53:17 +0200	[thread overview]
Message-ID: <200909021353.17091.kdudka@redhat.com> (raw)
In-Reply-To: <20090901232433.GC3947@josh-work.beaverton.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 4307 bytes --]

Well, let's go for the second iteration...

On Wed September 2 2009 01:24:33 Josh Triplett wrote:
> warnings:
> > static void foo(void) {
> >     enum ENUM_TYPE_A { VALUE_A } var_a;
> >     enum ENUM_TYPE_B { VALUE_B } var_b;
> >     enum /* anon. */ { VALUE_C } anon_enum_var;
> >     int i;
> >
> >     // always OK
> >     var_a = VALUE_A;
> >     var_a = (enum ENUM_TYPE_A) VALUE_B;
> >     var_b = (enum ENUM_TYPE_B) i;
> >     i = (int) VALUE_A;
>
> Fair enough; a cast should indeed make the warning go away.  Good catch
> to include the case of casting an enum value to a different enum type.
> I'd also suggest including some casts of values like 0 in the "always
> OK" section:
>
>     var_a = (enum ENUM_TYPE_B) 0;

This is IMO not "always OK":
warning: mixing different enum types
    int enum ENUM_TYPE_B  versus
    int enum ENUM_TYPE_A

Why should we have an exception for zero? Then we would not distinguish 
between VALUE_A and VALUE_B? This needs some justification. Have you 
considered the case that zero is even not valid at all for an enum?

> >     i = VALUE_B;
>
> Why does this not generate a warning with Wenum-to-int?  You should have
> to cast VALUE_B to int.

I was not sure if this is actually useful ... now it does.

> >     // caught by -Wint-to-enum (default)
> >     var_a = VALUE_B;
> >     var_b = VALUE_C;
> >     anon_enum_var = VALUE_A;
>
> Why does Wenum-mismatch not catch these?  Because it treats those
> constants as ints?  Regardless of the cause, this seems wrong.  If you
> explicitly declare a variable with enum type, assigning the wrong enum
> constant to it should generate a enum-mismatch warning, not an

Well, now caught by -Wenum-mismatch instead.

> int-to-enum warning.  However, I understand if this proves hard to fix,
> and generating *some* warning seems like an improvement over the current
> behavior of generating *no* warning.

Nope, it's easy to fix if you don't care about the change in behavior
of -Wenum-mismatch.

> >     var_a = 0;
> >     var_b = i;
> >     anon_enum_var = 0;
> >     anon_enum_var = i;
>
> I'd also suggest including tests with enum constants casted to integers:
>
>     var_a = (int) VALUE_A;
>     var_a = (int) VALUE_B;

Added.

> > --- a/sparse.1
> > +++ b/sparse.1
> > @@ -149,6 +149,18 @@ Sparse issues these warnings by default.  To turn
> > them off, use \fB\-Wno\-enum\-mismatch\fR.
> >  .
> >  .TP
> > +.B \-Wenum\-to\-int
> > +Warn about casting of an \fBenum\fR type to int and thus possible lost
> > of +information about the type.
>
> This should not say "warn about casting", because it specifically
> *doesn't* warn about casting.  s/casting of/converting/.
>
> I don't think "possible loss of information" seems like the reason to
> care about this warning.  These warnings just represent ways of getting
> sparse to make you treat enums as distinct types from int.  I'd suggest
> dropping the second half of the sentence.
>
> I'd also suggest adding something like "An explicit cast to int will
> suppress this warning.".

Fixed.

> > +.TP
> > +.B \-Wint\-to\-enum
> > +Warn about casting of int (or incompatible enumeration constant) to
> > \fBenum\fR.
>
> OK, so the test represents *documented* behavior, but it still doesn't
> seem right. :)  The "(or incompatible enumeration constant)" bit seems
> like it should become part of Wenum-mismatch.
>
> Or if necessary, perhaps part of some new flag, like
> Wenum-constant-mismatch, but that seems like overkill.
>
> s/casting of/converting/, as above.
>
> I'd also suggest adding "An explicit cast to the enum type will suppress
> this warning.".

Fixed.

I would really appreciate some native (or native like) speaker willing to 
reword my man page attempts completely. Any volunteer around? :-)

On Wed September 2 2009 02:27:08 Stephen Hemminger wrote:
> there is lots of code that does:
>
> enum {
>    my_register_1   = 0x001,
>    my_register_2   = 0x002,
> };
>
>
> foo(void) {
>    write_register(my_register_1, SETUP_VAL_X);
> ...
>
> So going from enum to int must be optional, but int to enum should
> trigger a warning.

This should be already working. If this is not the case, please write me
an minimal example along with the expected result. I'll take care of it...

> I'll give it a pass on the kernel for giggles.

Great!

Kamil

[-- Attachment #2: 0001-add-warnings-enum-to-int-and-int-to-enum.patch --]
[-- Type: text/x-patch, Size: 7546 bytes --]

From 381f635e581c3d346ae47672dc7be1423b681924 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Wed, 2 Sep 2009 13:17:57 +0200
Subject: [PATCH] add warnings enum-to-int and int-to-enum...

... and improve detection of the enum-mismatch warning

Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 evaluate.c   |   98 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 expression.h |    1 +
 lib.c        |    4 ++
 lib.h        |    2 +
 parse.c      |    1 +
 sparse.1     |   13 ++++++++
 6 files changed, 106 insertions(+), 13 deletions(-)

diff --git a/evaluate.c b/evaluate.c
index 805ae90..dfb7a0d 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -235,27 +235,94 @@ static int is_same_type(struct expression *expr, struct symbol *new)
 }
 
 static void
-warn_for_different_enum_types (struct position pos,
-			       struct symbol *typea,
-			       struct symbol *typeb)
+resolve_sym_node (struct symbol **psym)
 {
+	struct symbol *sym = *psym;
+	if (sym->type == SYM_NODE)
+		*psym = sym->ctype.base_type;
+}
+
+static void
+warn_for_different_enum_types (struct position pos, struct symbol *typea,
+			       struct symbol *typeb, struct symbol *enum_type)
+{
+	enum type ttypea;
 	if (!Wenum_mismatch)
 		return;
-	if (typea->type == SYM_NODE)
-		typea = typea->ctype.base_type;
-	if (typeb->type == SYM_NODE)
-		typeb = typeb->ctype.base_type;
+
+	resolve_sym_node(&typea);
+	resolve_sym_node(&typeb);
 
 	if (typea == typeb)
 		return;
+	if (typeb->type != SYM_ENUM)
+		return;
 
-	if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) {
+	ttypea = typea->type;
+	if (ttypea == SYM_ENUM || (ttypea == SYM_BASETYPE
+					&& enum_type && enum_type != typeb))
+	{
 		warning(pos, "mixing different enum types");
-		info(pos, "    %s versus", show_typename(typea));
+		info(pos, "    %s versus", show_typename((ttypea == SYM_ENUM)
+					? typea
+					: enum_type));
 		info(pos, "    %s", show_typename(typeb));
 	}
 }
 
+static void
+issue_conversion_warning(struct position pos,
+			 struct symbol *typea,
+			 struct symbol *typeb)
+{
+	warning(pos, "conversion of");
+	info(pos, "    %s to", show_typename(typea));
+	info(pos, "    %s", show_typename(typeb));
+}
+
+static void
+warn_for_enum_to_int_cast (struct expression *expr, struct symbol *typeb)
+{
+	struct position pos = expr->pos;
+	struct symbol *typea = expr->ctype;
+	struct symbol *enum_type = expr->enum_type;
+
+	if (!Wenum_to_int)
+		return;
+
+	resolve_sym_node(&typea);
+	resolve_sym_node(&typeb);
+
+	if (typeb->type != SYM_BASETYPE)
+		return;
+
+	if (typea->type == SYM_ENUM && typea->ident)
+		issue_conversion_warning(pos, typea, typeb);
+
+	if (typea->type == SYM_BASETYPE && enum_type && enum_type->ident)
+		issue_conversion_warning(pos, enum_type, typeb);
+}
+
+static void
+warn_for_int_to_enum_cast (struct expression *expr, struct symbol *typeb)
+{
+	struct position pos = expr->pos;
+	struct symbol *typea = expr->ctype;
+	struct symbol *enum_type = expr->enum_type;
+
+	if (!Wint_to_enum)
+		return;
+
+	resolve_sym_node(&typea);
+	resolve_sym_node(&typeb);
+
+	if (typea->type != SYM_BASETYPE || typeb->type != SYM_ENUM)
+		return;
+
+	if (!enum_type)
+		issue_conversion_warning(pos, typea, typeb);
+}
+
 /*
  * This gets called for implicit casts in assignments and
  * integer promotion. We often want to try to move the
@@ -267,7 +334,10 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
 {
 	struct expression *expr;
 
-	warn_for_different_enum_types (old->pos, old->ctype, type);
+	warn_for_different_enum_types (old->pos, old->ctype, type,
+				       old->enum_type);
+	warn_for_enum_to_int_cast (old, type);
+	warn_for_int_to_enum_cast (old, type);
 
 	if (old->ctype != &null_ctype && is_same_type(old, type))
 		return old;
@@ -287,7 +357,7 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
 		break;
 
 	case EXPR_IMPLIED_CAST:
-		warn_for_different_enum_types(old->pos, old->ctype, type);
+		warn_for_different_enum_types(old->pos, old->ctype, type, NULL);
 
 		if (old->ctype->bit_size >= type->bit_size) {
 			struct expression *orig = old->cast_expression;
@@ -498,7 +568,8 @@ static struct symbol *usual_conversions(int op,
 {
 	struct symbol *ctype;
 
-	warn_for_different_enum_types(right->pos, left->ctype, right->ctype);
+	warn_for_different_enum_types(right->pos, left->ctype, right->ctype,
+				      NULL);
 
 	if ((lclass | rclass) & TYPE_RESTRICT)
 		goto Restr;
@@ -3241,7 +3312,8 @@ static void check_case_type(struct expression *switch_expr,
 		goto Bad;
 	if (enumcase) {
 		if (*enumcase)
-			warn_for_different_enum_types(case_expr->pos, case_type, (*enumcase)->ctype);
+			warn_for_different_enum_types(case_expr->pos, case_type,
+						      (*enumcase)->ctype, NULL);
 		else if (is_enum_type(case_type))
 			*enumcase = case_expr;
 	}
diff --git a/expression.h b/expression.h
index 631224f..81f70ad 100644
--- a/expression.h
+++ b/expression.h
@@ -70,6 +70,7 @@ struct expression {
 		struct {
 			unsigned long long value;
 			unsigned taint;
+			struct symbol *enum_type;
 		};
 
 		// EXPR_FVALUE
diff --git a/lib.c b/lib.c
index 600939b..2f78bd5 100644
--- a/lib.c
+++ b/lib.c
@@ -199,6 +199,8 @@ int Wdecl = 1;
 int Wdefault_bitfield_sign = 0;
 int Wdo_while = 0;
 int Wenum_mismatch = 1;
+int Wenum_to_int = 0;
+int Wint_to_enum = 1;
 int Wnon_pointer_null = 1;
 int Wold_initializer = 1;
 int Wone_bit_signed_bitfield = 1;
@@ -380,6 +382,8 @@ static const struct warning {
 	{ "default-bitfield-sign", &Wdefault_bitfield_sign },
 	{ "do-while", &Wdo_while },
 	{ "enum-mismatch", &Wenum_mismatch },
+	{ "enum-to-int", &Wenum_to_int },
+	{ "int-to-enum", &Wint_to_enum },
 	{ "non-pointer-null", &Wnon_pointer_null },
 	{ "old-initializer", &Wold_initializer },
 	{ "one-bit-signed-bitfield", &Wone_bit_signed_bitfield },
diff --git a/lib.h b/lib.h
index b22fa93..962d49d 100644
--- a/lib.h
+++ b/lib.h
@@ -96,6 +96,8 @@ extern int Wdecl;
 extern int Wdefault_bitfield_sign;
 extern int Wdo_while;
 extern int Wenum_mismatch;
+extern int Wenum_to_int;
+extern int Wint_to_enum;
 extern int Wnon_pointer_null;
 extern int Wold_initializer;
 extern int Wone_bit_signed_bitfield;
diff --git a/parse.c b/parse.c
index 5e75242..76d4c58 100644
--- a/parse.c
+++ b/parse.c
@@ -791,6 +791,7 @@ static void cast_enum_list(struct symbol_list *list, struct symbol *base_type)
 		if (expr->type != EXPR_VALUE)
 			continue;
 		ctype = expr->ctype;
+		expr->enum_type = sym->ctype.base_type;
 		if (ctype->bit_size == base_type->bit_size)
 			continue;
 		cast_value(expr, base_type, expr, ctype);
diff --git a/sparse.1 b/sparse.1
index d7fe444..288b3a8 100644
--- a/sparse.1
+++ b/sparse.1
@@ -149,6 +149,19 @@ Sparse issues these warnings by default.  To turn them off, use
 \fB\-Wno\-enum\-mismatch\fR.
 .
 .TP
+.B \-Wenum\-to\-int
+Warn about converting an \fBenum\fR type to int. An explicit cast to int will
+suppress this warning.
+.
+.TP
+.B \-Wint\-to\-enum
+Warn about converting int to \fBenum\fR type. An explicit cast to the right
+\fBenum\fR type will suppress this warning.
+
+Sparse issues these warnings by default.  To turn them off, use
+\fB\-Wno\-int\-to\-enum\fR.
+.
+.TP
 .B \-Wnon\-pointer\-null
 Warn about the use of 0 as a NULL pointer.
 
-- 
1.6.2.5


[-- Attachment #3: test-enum.c --]
[-- Type: text/x-csrc, Size: 941 bytes --]

static void foo(void) {
    enum ENUM_TYPE_A { VALUE_A } var_a;
    enum ENUM_TYPE_B { VALUE_B } var_b;
    enum /* anon. */ { VALUE_C } anon_enum_var;
    int i;

    // always OK
    var_a = VALUE_A;
    var_a = (enum ENUM_TYPE_A) VALUE_B;
    var_b = (enum ENUM_TYPE_B) i;
    i = (int) VALUE_A;
    anon_enum_var = VALUE_C;
    i = VALUE_C;
    i = anon_enum_var;
    i = 7;

    // caught by -Wenum-mismatch (default) even without the patch
    var_a = var_b;
    var_b = anon_enum_var;
    anon_enum_var = var_a;
    var_a = (enum ENUM_TYPE_B) 0;

    // caught by -Wenum-mismatch (default) only with the patch applied
    var_a = VALUE_B;
    var_b = VALUE_C;
    anon_enum_var = VALUE_A;

    // caught by -Wint-to-enum (default)
    var_a = 0;
    var_b = i;
    anon_enum_var = 0;
    anon_enum_var = i;
    var_a = (int) VALUE_A;
    var_a = (int) VALUE_B;

    // caught only with -Wenum-to-int
    i = var_a;
    i = VALUE_B;
}

  parent reply	other threads:[~2009-09-02 11:53 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-30 22:32 sparse segv with simple test Stephen Hemminger
2009-08-30 22:53 ` Kamil Dudka
2009-08-31 15:57   ` Stephen Hemminger
2009-08-31 18:12     ` Kamil Dudka
2009-08-31 18:49       ` Stephen Hemminger
2009-08-31 19:04         ` Kamil Dudka
2009-08-31 20:53           ` Josh Triplett
2009-09-01 21:59             ` [PATCH] add warnings enum-to-int and int-to-enum Kamil Dudka
2009-09-01 23:24               ` Josh Triplett
2009-09-02  0:27                 ` Stephen Hemminger
2009-09-02 17:56                   ` Daniel Barkalow
2009-09-02 18:04                     ` Kamil Dudka
2009-09-02 18:43                       ` Daniel Barkalow
2009-09-02 18:56                         ` Josh Triplett
2009-09-02 19:19                           ` Daniel Barkalow
2009-09-02 19:58                             ` Kamil Dudka
2009-09-02 11:53                 ` Kamil Dudka [this message]
2009-09-02 15:21                   ` Josh Triplett
2009-09-02 16:23                     ` Kamil Dudka
2009-09-02 16:38                       ` Christopher Li
2009-09-02 19:03                       ` Josh Triplett
2009-09-02 19:19                         ` Kamil Dudka
2009-09-02 22:35                           ` Kamil Dudka
2009-09-03  9:42                             ` Christopher Li
2009-09-03 11:47                               ` Kamil Dudka
2009-09-03 18:38                                 ` Christopher Li
2009-09-03 18:54                                   ` Kamil Dudka
2009-09-03 20:02                                     ` Christopher Li
2009-09-13 19:28                                       ` Kamil Dudka
2009-09-13 19:55                                         ` Christopher Li
2009-09-13 20:09                                           ` Kamil Dudka

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=200909021353.17091.kdudka@redhat.com \
    --to=kdudka@redhat.com \
    --cc=josh@joshtriplett.org \
    --cc=linux-sparse@vger.kernel.org \
    --cc=shemminger@vyatta.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.