Skip to content

Commit

Permalink
Merge branch 'union-cast' into master
Browse files Browse the repository at this point in the history
* teach sparse about union casts
  • Loading branch information
lucvoo committed Aug 18, 2020
2 parents ad7af43 + 8b3cbf5 commit 1016492
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 20 deletions.
5 changes: 5 additions & 0 deletions Documentation/release-notes/v0.6.3.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
v0.6.3 (2020-xx-xy)
===================

* Changes in warnings:
"warning: cast to union type" [disable with -Wno-union-cast]
88 changes: 68 additions & 20 deletions evaluate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2946,11 +2946,52 @@ static int cast_flags(struct expression *expr, struct expression *old)
return flags;
}

///
// check if a type matches one of the members of a union type
// @utype: the union type
// @type: to type to check
// @return: to identifier of the matching type in the union.
static struct symbol *find_member_type(struct symbol *utype, struct symbol *type)
{
struct symbol *t, *member;

if (utype->type != SYM_UNION)
return NULL;

FOR_EACH_PTR(utype->symbol_list, member) {
classify_type(member, &t);
if (type == t)
return member;
} END_FOR_EACH_PTR(member);
return NULL;
}

static struct symbol *evaluate_compound_literal(struct expression *expr, struct expression *source)
{
struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
struct symbol *sym = expr->cast_type;

sym->initializer = source;
evaluate_symbol(sym);

addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
addr->symbol = sym;
if (sym->ctype.modifiers & MOD_TOPLEVEL)
addr->flags |= CEF_ADDR;

expr->type = EXPR_PREOP;
expr->op = '*';
expr->deref = addr;
expr->ctype = sym;
return sym;
}

static struct symbol *evaluate_cast(struct expression *expr)
{
struct expression *source = expr->cast_expression;
struct symbol *ctype;
struct symbol *ttype, *stype;
struct symbol *member;
int tclass, sclass;
struct ident *tas = NULL, *sas = NULL;

Expand All @@ -2968,25 +3009,8 @@ static struct symbol *evaluate_cast(struct expression *expr)
* dereferenced as part of a post-fix expression.
* We need to produce an expression that can be dereferenced.
*/
if (source->type == EXPR_INITIALIZER) {
struct symbol *sym = expr->cast_type;
struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);

sym->initializer = source;
evaluate_symbol(sym);

addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
addr->symbol = sym;
if (sym->ctype.modifiers & MOD_TOPLEVEL)
addr->flags |= CEF_ADDR;

expr->type = EXPR_PREOP;
expr->op = '*';
expr->unop = addr;
expr->ctype = sym;

return sym;
}
if (source->type == EXPR_INITIALIZER)
return evaluate_compound_literal(expr, source);

ctype = examine_symbol_type(expr->cast_type);
expr->ctype = ctype;
Expand Down Expand Up @@ -3017,8 +3041,32 @@ static struct symbol *evaluate_cast(struct expression *expr)
if (expr->type == EXPR_FORCE_CAST)
goto out;

if (tclass & (TYPE_COMPOUND | TYPE_FN))
if (tclass & (TYPE_COMPOUND | TYPE_FN)) {
/*
* Special case: cast to union type (GCC extension)
* The effect is similar to a compound literal except
* that the result is a rvalue.
*/
if ((member = find_member_type(ttype, stype))) {
struct expression *item, *init;

if (Wunion_cast)
warning(expr->pos, "cast to union type");

item = alloc_expression(source->pos, EXPR_IDENTIFIER);
item->expr_ident = member->ident;
item->ident_expression = source;

init = alloc_expression(source->pos, EXPR_INITIALIZER);
add_expression(&init->expr_list, item);

// FIXME: this should be a rvalue
evaluate_compound_literal(expr, init);
return ctype;
}

warning(expr->pos, "cast to non-scalar");
}

if (sclass & TYPE_COMPOUND)
warning(expr->pos, "cast from non-scalar");
Expand Down
2 changes: 2 additions & 0 deletions options.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ int Wtransparent_union = 0;
int Wtypesign = 0;
int Wundef = 0;
int Wuninitialized = 1;
int Wunion_cast = 0;
int Wuniversal_initializer = 0;
int Wunknown_attribute = 0;
int Wvla = 1;
Expand Down Expand Up @@ -868,6 +869,7 @@ static const struct flag warnings[] = {
{ "typesign", &Wtypesign },
{ "undef", &Wundef },
{ "uninitialized", &Wuninitialized },
{ "union-cast", &Wunion_cast },
{ "universal-initializer", &Wuniversal_initializer },
{ "unknown-attribute", &Wunknown_attribute },
{ "vla", &Wvla },
Expand Down
1 change: 1 addition & 0 deletions options.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ extern int Wtransparent_union;
extern int Wtypesign;
extern int Wundef;
extern int Wuninitialized;
extern int Wunion_cast;
extern int Wuniversal_initializer;
extern int Wunknown_attribute;
extern int Wvla;
Expand Down
6 changes: 6 additions & 0 deletions sparse.1
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,12 @@ The concerned warnings are, for example, those triggered by
Sparse does not issue these warnings by default, processing '{\ 0\ }'
the same as '{\ }'.
.
.TP
.B -Wunion-cast
Warn on casts to union types.

Sparse does not issues these warnings by default.
.
.SH MISC OPTIONS
.TP
.B \-\-arch=\fIARCH\fR
Expand Down
23 changes: 23 additions & 0 deletions validation/eval/union-cast-no.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
union u {
int i;
char x[8];
};

static union u foo(int i)
{
return (union u)i;
}

static union u bar(long l)
{
return (union u)l;
}

/*
* check-name: union-cast-no
* check-command: sparse -Wno-union-cast $file
*
* check-error-start
eval/union-cast-no.c:13:17: warning: cast to non-scalar
* check-error-end
*/
24 changes: 24 additions & 0 deletions validation/eval/union-cast.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
union u {
int i;
char x[8];
};

static union u foo(int a)
{
return (union u)a;
}

static union u bar(long a)
{
return (union u)a;
}

/*
* check-name: union-cast
* check-command: sparse -Wunion-cast $file
*
* check-error-start
eval/union-cast.c:8:17: warning: cast to union type
eval/union-cast.c:13:17: warning: cast to non-scalar
* check-error-end
*/

0 comments on commit 1016492

Please sign in to comment.