aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--evaluate.c38
-rw-r--r--expand.c87
-rw-r--r--memops.c11
-rw-r--r--parse.c10
-rw-r--r--ptrlist.c6
-rw-r--r--show-parse.c6
-rw-r--r--symbol.c51
-rw-r--r--validation/backend/hello.c2
-rw-r--r--validation/backend/sum.c3
-rw-r--r--validation/bitfield-sizes.c30
-rw-r--r--validation/c11-atomic.c12
-rw-r--r--validation/eval/addressable-complex.c23
-rw-r--r--validation/eval/addressable-degen.c17
-rw-r--r--validation/eval/premature-examination.c27
-rw-r--r--validation/expand/constant-init-array.c15
-rw-r--r--validation/expand/constant-init-nested-array.c15
-rw-r--r--validation/expand/constant-init-nested-struct.c23
-rw-r--r--validation/expand/constant-init-string.c15
-rw-r--r--validation/expand/constant-union-flt2int.c20
-rw-r--r--validation/expand/constant-union-int2flt.c19
-rw-r--r--validation/expand/constant-union-size.c (renamed from validation/bug-expand-union0.c)7
-rw-r--r--validation/expand/cost-deref-nested.c20
-rw-r--r--validation/expand/default-init-array.c16
-rw-r--r--validation/expand/default-init-struct.c22
-rw-r--r--validation/expand/union-cast.c27
-rw-r--r--validation/function-redecl.c50
-rw-r--r--validation/memops/type-punning-flt2int.c (renamed from validation/bug-expand-union1.c)5
-rw-r--r--validation/memops/type-punning-int2flt.c19
-rw-r--r--validation/nocast.c10
-rw-r--r--validation/restrict.c12
-rw-r--r--validation/typedef-redef.c5
31 files changed, 534 insertions, 89 deletions
diff --git a/evaluate.c b/evaluate.c
index 19bdab92..f1a266be 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -110,6 +110,8 @@ static struct symbol *evaluate_string(struct expression *expr)
sym->ctype.modifiers = MOD_STATIC;
sym->ctype.base_type = array;
sym->initializer = initstr;
+ sym->examined = 1;
+ sym->evaluated = 1;
initstr->ctype = sym;
initstr->string = expr->string;
@@ -119,6 +121,8 @@ static struct symbol *evaluate_string(struct expression *expr)
array->ctype.alignment = 1;
array->ctype.modifiers = MOD_STATIC;
array->ctype.base_type = &char_ctype;
+ array->examined = 1;
+ array->evaluated = 1;
addr->symbol = sym;
addr->ctype = &lazy_ptr_ctype;
@@ -379,10 +383,8 @@ static inline int classify_type(struct symbol *type, struct symbol **base)
if (type->type == SYM_NODE)
type = type->ctype.base_type;
if (type->type == SYM_TYPEOF) {
- type = evaluate_expression(type->initializer);
- if (!type)
- type = &bad_ctype;
- else if (type->type == SYM_NODE)
+ type = examine_symbol_type(type);
+ if (type->type == SYM_NODE)
type = type->ctype.base_type;
}
if (type->type == SYM_ENUM)
@@ -1501,9 +1503,9 @@ static int compatible_assignment_types(struct expression *expr, struct symbol *t
struct expression **rp, const char *where)
{
const char *typediff;
- struct symbol *source = degenerate(*rp);
if (!check_assignment_types(target, rp, &typediff)) {
+ struct symbol *source = *rp ? (*rp)->ctype : NULL;
warning(expr->pos, "incorrect type in %s (%s)", where, typediff);
info(expr->pos, " expected %s", show_typename(target));
info(expr->pos, " got %s", show_typename(source));
@@ -1540,6 +1542,16 @@ static int compatible_argument_type(struct expression *expr, struct symbol *targ
return compatible_assignment_types(expr, target, rp, where);
}
+static void mark_addressable(struct expression *expr)
+{
+ while (expr->type == EXPR_BINOP && expr->op == '+')
+ expr = expr->left;
+ if (expr->type == EXPR_SYMBOL) {
+ struct symbol *sym = expr->symbol;
+ sym->ctype.modifiers |= MOD_ADDRESSABLE;
+ }
+}
+
static void mark_assigned(struct expression *expr)
{
struct symbol *sym;
@@ -1762,6 +1774,7 @@ static struct symbol *degenerate(struct expression *expr)
*expr = *expr->unop;
ctype = create_pointer(expr, ctype, 1);
expr->ctype = ctype;
+ mark_addressable(expr);
default:
/* nothing */;
}
@@ -1780,10 +1793,7 @@ static struct symbol *evaluate_addressof(struct expression *expr)
ctype = op->ctype;
*expr = *op->unop;
- if (expr->type == EXPR_SYMBOL) {
- struct symbol *sym = expr->symbol;
- sym->ctype.modifiers |= MOD_ADDRESSABLE;
- }
+ mark_addressable(expr);
/*
* symbol expression evaluation is lazy about the type
@@ -1817,7 +1827,6 @@ static struct symbol *evaluate_dereference(struct expression *expr)
ctype = ctype->ctype.base_type;
target = ctype->ctype.base_type;
- examine_symbol_type(target);
switch (ctype->type) {
default:
@@ -1827,6 +1836,7 @@ static struct symbol *evaluate_dereference(struct expression *expr)
*expr = *op;
return expr->ctype;
case SYM_PTR:
+ examine_symbol_type(target);
node = alloc_symbol(expr->pos, SYM_NODE);
node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
merge_type(node, ctype);
@@ -3380,9 +3390,11 @@ void check_duplicates(struct symbol *sym)
declared++;
typediff = type_difference(&sym->ctype, &next->ctype, 0, 0);
if (typediff) {
- sparse_error(sym->pos, "symbol '%s' redeclared with different type (originally declared at %s:%d) - %s",
- show_ident(sym->ident),
- stream_name(next->pos.stream), next->pos.line, typediff);
+ sparse_error(sym->pos, "symbol '%s' redeclared with different type (%s):",
+ show_ident(sym->ident), typediff);
+ info(sym->pos, " %s", show_typename(sym));
+ info(next->pos, "note: previously declared as:");
+ info(next->pos, " %s", show_typename(next));
return;
}
}
diff --git a/expand.c b/expand.c
index ae764153..36612c86 100644
--- a/expand.c
+++ b/expand.c
@@ -621,12 +621,70 @@ static int expand_addressof(struct expression *expr)
return expand_expression(expr->unop);
}
+///
+// lookup the type of a struct's memeber at the requested offset
+static struct symbol *find_member(struct symbol *sym, int offset)
+{
+ struct ptr_list *head, *list;
+
+ head = (struct ptr_list *) sym->symbol_list;
+ list = head;
+ if (!head)
+ return NULL;
+ do {
+ int nr = list->nr;
+ int i;
+ for (i = 0; i < nr; i++) {
+ struct symbol *ent = (struct symbol *) list->list[i];
+ int curr = ent->offset;
+ if (curr == offset)
+ return ent;
+ if (curr > offset)
+ return NULL;
+ }
+ } while ((list = list->next) != head);
+ return NULL;
+}
+
+///
+// lookup a suitable default initializer value at the requested offset
+static struct expression *default_initializer(struct symbol *sym, int offset)
+{
+ static struct expression value;
+ struct symbol *type;
+
+redo:
+ switch (sym->type) {
+ case SYM_NODE:
+ sym = sym->ctype.base_type;
+ goto redo;
+ case SYM_STRUCT:
+ type = find_member(sym, offset);
+ if (!type)
+ return NULL;
+ break;
+ case SYM_ARRAY:
+ type = sym->ctype.base_type;
+ break;
+ default:
+ return NULL;
+ }
+
+ if (is_integral_type(type))
+ value.type = EXPR_VALUE;
+ else if (is_float_type(type))
+ value.type = EXPR_FVALUE;
+ else
+ return NULL;
+
+ value.ctype = type;
+ return &value;
+}
+
/*
* Look up a trustable initializer value at the requested offset.
*
* Return NULL if no such value can be found or statically trusted.
- *
- * FIXME!! We should check that the size is right!
*/
static struct expression *constant_symbol_value(struct symbol *sym, int offset)
{
@@ -648,10 +706,11 @@ static struct expression *constant_symbol_value(struct symbol *sym, int offset)
if (entry->init_offset < offset)
continue;
if (entry->init_offset > offset)
- return NULL;
+ break;
return entry->init_expr;
} END_FOR_EACH_PTR(entry);
- return NULL;
+
+ value = default_initializer(sym, offset);
}
return value;
}
@@ -678,22 +737,26 @@ static int expand_dereference(struct expression *expr)
* Is it "symbol" or "symbol + offset"?
*/
offset = 0;
- if (unop->type == EXPR_BINOP && unop->op == '+') {
+ while (unop->type == EXPR_BINOP && unop->op == '+') {
struct expression *right = unop->right;
- if (right->type == EXPR_VALUE) {
- offset = right->value;
- unop = unop->left;
- }
+ if (right->type != EXPR_VALUE)
+ break;
+ offset += right->value;
+ unop = unop->left;
}
if (unop->type == EXPR_SYMBOL) {
struct symbol *sym = unop->symbol;
+ struct symbol *ctype = expr->ctype;
struct expression *value = constant_symbol_value(sym, offset);
/* Const symbol with a constant initializer? */
- if (value) {
- /* FIXME! We should check that the size is right! */
+ if (value && value->ctype) {
+ if (ctype->bit_size != value->ctype->bit_size)
+ return UNSAFE;
if (value->type == EXPR_VALUE) {
+ if (!is_integral_type(ctype))
+ return UNSAFE;
if (is_bitfield_type(value->ctype))
return UNSAFE;
expr->type = EXPR_VALUE;
@@ -701,6 +764,8 @@ static int expand_dereference(struct expression *expr)
expr->taint = 0;
return 0;
} else if (value->type == EXPR_FVALUE) {
+ if (!is_float_type(ctype))
+ return UNSAFE;
expr->type = EXPR_FVALUE;
expr->fvalue = value->fvalue;
return 0;
diff --git a/memops.c b/memops.c
index 5df2c033..f071e556 100644
--- a/memops.c
+++ b/memops.c
@@ -82,6 +82,15 @@ static int local_pseudo(pseudo_t pseudo)
&& !address_taken(pseudo);
}
+static bool compatible_loads(struct instruction *a, struct instruction *b)
+{
+ if (is_integral_type(a->type) && is_float_type(b->type))
+ return false;
+ if (is_float_type(a->type) && is_integral_type(b->type))
+ return false;
+ return true;
+}
+
static void simplify_loads(struct basic_block *bb)
{
struct instruction *insn;
@@ -114,6 +123,8 @@ static void simplify_loads(struct basic_block *bb)
continue;
goto next_load;
}
+ if (!compatible_loads(insn, dom))
+ goto next_load;
/* Yeehaa! Found one! */
convert_load_instruction(insn, dom->target);
goto next_load;
diff --git a/parse.c b/parse.c
index 6db3cba7..fb05253b 100644
--- a/parse.c
+++ b/parse.c
@@ -1946,12 +1946,9 @@ static struct token *handle_bitfield(struct token *token, struct decl_state *ctx
width = const_expression_value(expr);
bitfield->bit_size = width;
- if (width < 0 || width > INT_MAX) {
- sparse_error(token->pos, "invalid bitfield width, %lld.", width);
- width = -1;
- } else if (*ctx->ident && width == 0) {
- sparse_error(token->pos, "invalid named zero-width bitfield `%s'",
- show_ident(*ctx->ident));
+ if (width < 0 || width > INT_MAX || (*ctx->ident && width == 0)) {
+ sparse_error(token->pos, "bitfield '%s' has invalid width (%lld)",
+ show_ident(*ctx->ident), width);
width = -1;
} else if (*ctx->ident) {
struct symbol *base_type = bitfield->ctype.base_type;
@@ -1972,6 +1969,7 @@ static struct token *handle_bitfield(struct token *token, struct decl_state *ctx
}
bitfield->bit_size = width;
bitfield->endpos = token->pos;
+ bitfield->ident = *ctx->ident;
return token;
}
diff --git a/ptrlist.c b/ptrlist.c
index 0fb28127..3af0b2c5 100644
--- a/ptrlist.c
+++ b/ptrlist.c
@@ -215,7 +215,7 @@ restart:
///
// split a ptrlist block
-// @head: the ptrlist block to be splitted
+// @head: the ptrlist block to be split
//
// A new block is inserted just after @head and the entries
// at the half end of @head are moved to this new block.
@@ -363,7 +363,7 @@ out:
///
// remove the last entry of a ptrlist
// @head: a pointer to the list
-// @return: the last elemant of the list or NULL if the list is empty.
+// @return: the last element of the list or NULL if the list is empty.
//
// :note: this doesn't repack the list
void * undo_ptr_list_last(struct ptr_list **head)
@@ -389,7 +389,7 @@ void * undo_ptr_list_last(struct ptr_list **head)
///
// remove the last entry and repack the list
// @head: a pointer to the list
-// @return: the last elemant of the list or NULL if the list is empty.
+// @return: the last element of the list or NULL if the list is empty.
void * delete_ptr_list_last(struct ptr_list **head)
{
void *ptr = NULL;
diff --git a/show-parse.c b/show-parse.c
index f0ea9cae..044465e9 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -300,12 +300,12 @@ deeper:
if (as)
prepend(name, "%s ", show_as(as));
- if (sym->type == SYM_BASETYPE || sym->type == SYM_ENUM)
+ if (sym && (sym->type == SYM_BASETYPE || sym->type == SYM_ENUM))
mod &= ~MOD_SPECIFIER;
s = modifier_string(mod);
len = strlen(s);
- name->start -= len;
- memcpy(name->start, s, len);
+ name->start -= len;
+ memcpy(name->start, s, len);
mod = 0;
as = NULL;
}
diff --git a/symbol.c b/symbol.c
index fb14b624..ab6e9841 100644
--- a/symbol.c
+++ b/symbol.c
@@ -254,13 +254,15 @@ static struct symbol * examine_array_type(struct symbol *sym)
static struct symbol *examine_bitfield_type(struct symbol *sym)
{
struct symbol *base_type = examine_base_type(sym);
- unsigned long bit_size, alignment, modifiers;
+ unsigned long alignment, modifiers;
if (!base_type)
return sym;
- bit_size = base_type->bit_size;
- if (sym->bit_size > bit_size)
- warning(sym->pos, "impossible field-width, %d, for this type", sym->bit_size);
+ if (sym->bit_size > base_type->bit_size) {
+ sparse_error(sym->pos, "bitfield '%s' is wider (%d) than its type (%s)",
+ show_ident(sym->ident), sym->bit_size, show_typename(base_type));
+ sym->bit_size = -1;
+ }
alignment = base_type->ctype.alignment;
if (!sym->ctype.alignment)
@@ -451,6 +453,25 @@ static struct symbol *examine_pointer_type(struct symbol *sym)
return sym;
}
+static struct symbol *examine_typeof(struct symbol *sym)
+{
+ struct symbol *base = evaluate_expression(sym->initializer);
+ unsigned long mod = 0;
+
+ if (!base)
+ base = &bad_ctype;
+ if (base->type == SYM_NODE) {
+ mod |= base->ctype.modifiers & MOD_TYPEOF;
+ base = base->ctype.base_type;
+ }
+ if (base->type == SYM_BITFIELD)
+ warning(base->pos, "typeof applied to bitfield type");
+ sym->type = SYM_NODE;
+ sym->ctype.modifiers = mod;
+ sym->ctype.base_type = base;
+ return examine_node_type(sym);
+}
+
/*
* Fill in type size and alignment information for
* regular SYM_TYPE things.
@@ -484,26 +505,8 @@ struct symbol *examine_symbol_type(struct symbol * sym)
case SYM_BASETYPE:
/* Size and alignment had better already be set up */
return sym;
- case SYM_TYPEOF: {
- struct symbol *base = evaluate_expression(sym->initializer);
- if (base) {
- unsigned long mod = 0;
-
- if (is_bitfield_type(base))
- warning(base->pos, "typeof applied to bitfield type");
- if (base->type == SYM_NODE) {
- mod |= base->ctype.modifiers & MOD_TYPEOF;
- base = base->ctype.base_type;
- }
- sym->type = SYM_NODE;
- sym->ctype.modifiers = mod;
- sym->ctype.base_type = base;
- return examine_node_type(sym);
- }
- sym->type = SYM_NODE;
- sym->ctype.base_type = &bad_ctype;
- return sym;
- }
+ case SYM_TYPEOF:
+ return examine_typeof(sym);
case SYM_PREPROCESSOR:
sparse_error(sym->pos, "ctype on preprocessor command? (%s)", show_ident(sym->ident));
return NULL;
diff --git a/validation/backend/hello.c b/validation/backend/hello.c
index b0e514be..eb89846f 100644
--- a/validation/backend/hello.c
+++ b/validation/backend/hello.c
@@ -1,4 +1,4 @@
-#include <stdio.h>
+int puts(const char *s);
int main(int argc, char *argv[])
{
diff --git a/validation/backend/sum.c b/validation/backend/sum.c
index fa51120e..38ebf41e 100644
--- a/validation/backend/sum.c
+++ b/validation/backend/sum.c
@@ -1,5 +1,4 @@
-#include <stdio.h>
-#include <stdlib.h>
+int printf(const char * fmt, ...);
static int sum(int n)
{
diff --git a/validation/bitfield-sizes.c b/validation/bitfield-sizes.c
new file mode 100644
index 00000000..9f76d074
--- /dev/null
+++ b/validation/bitfield-sizes.c
@@ -0,0 +1,30 @@
+struct a {
+ int a:31;
+ int b:32;
+ long c:63;
+ long d:64;
+ int x:33; // KO
+ long y:65; // KO
+};
+static struct a a;
+
+struct b {
+ int m1:-1; // KO
+ int x1:2147483648; // KO
+ int :0;
+ int a0:0; // KO
+};
+static struct b b;
+
+/*
+ * check-name: bitfield-sizes
+ * check-command: sparse -m64 $file
+ *
+ * check-error-start
+bitfield-sizes.c:12:18: error: bitfield 'm1' has invalid width (-1)
+bitfield-sizes.c:13:26: error: bitfield 'x1' has invalid width (2147483648)
+bitfield-sizes.c:15:17: error: bitfield 'a0' has invalid width (0)
+bitfield-sizes.c:6:15: error: bitfield 'x' is wider (33) than its type (int)
+bitfield-sizes.c:7:15: error: bitfield 'y' is wider (65) than its type (long)
+ * check-error-end
+ */
diff --git a/validation/c11-atomic.c b/validation/c11-atomic.c
index e87d06cd..17720861 100644
--- a/validation/c11-atomic.c
+++ b/validation/c11-atomic.c
@@ -66,11 +66,17 @@ void baz(void)
/*
* check-name: C11 _Atomic type qualifier
- * check-command: sparse -Wno-decl $file;
+ * check-command: sparse -Wno-decl $file
*
* check-error-start
-c11-atomic.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at c11-atomic.c:3) - incompatible argument 1 (different modifiers)
-c11-atomic.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at c11-atomic.c:4) - incompatible argument 1 (different modifiers)
+c11-atomic.c:11:6: error: symbol 'f02' redeclared with different type (incompatible argument 1 (different modifiers)):
+c11-atomic.c:11:6: void extern [addressable] [toplevel] f02( ... )
+c11-atomic.c:3:6: note: previously declared as:
+c11-atomic.c:3:6: void extern [addressable] [toplevel] f02( ... )
+c11-atomic.c:12:6: error: symbol 'f03' redeclared with different type (incompatible argument 1 (different modifiers)):
+c11-atomic.c:12:6: void extern [addressable] [toplevel] f03( ... )
+c11-atomic.c:4:6: note: previously declared as:
+c11-atomic.c:4:6: void extern [addressable] [toplevel] f03( ... )
c11-atomic.c:33:13: warning: incorrect type in assignment (different modifiers)
c11-atomic.c:33:13: expected int *extern [assigned] puo
c11-atomic.c:33:13: got int const *
diff --git a/validation/eval/addressable-complex.c b/validation/eval/addressable-complex.c
new file mode 100644
index 00000000..e3d4aca4
--- /dev/null
+++ b/validation/eval/addressable-complex.c
@@ -0,0 +1,23 @@
+extern void def(void *);
+
+struct s1 {
+ int a;
+};
+
+int use1(void)
+{
+ struct s1 s = { 3 };
+
+ def(&s.a);
+
+ return s.a;
+}
+
+/*
+ * check-name: eval/addressable-complex
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ * check-output-excludes: return\\..*\\$3
+ */
diff --git a/validation/eval/addressable-degen.c b/validation/eval/addressable-degen.c
new file mode 100644
index 00000000..d420927e
--- /dev/null
+++ b/validation/eval/addressable-degen.c
@@ -0,0 +1,17 @@
+extern void def(void *, unsigned int);
+
+static int bar(void)
+{
+ int x[2] = { 1, 2 };
+
+ def(x, sizeof(x));
+ return x[1];
+}
+
+/*
+ * check-name: eval/addressable-degen
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
diff --git a/validation/eval/premature-examination.c b/validation/eval/premature-examination.c
new file mode 100644
index 00000000..bd2ffa90
--- /dev/null
+++ b/validation/eval/premature-examination.c
@@ -0,0 +1,27 @@
+extern int i;
+
+int foo(void)
+{
+ return *i;
+}
+
+int bar(void)
+{
+ return i[0];
+}
+
+int *qux(void)
+{
+ return &i[0];
+}
+
+/*
+ * check-name: premature-examination
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+eval/premature-examination.c:5:16: error: cannot dereference this type
+eval/premature-examination.c:10:17: error: cannot dereference this type
+eval/premature-examination.c:15:18: error: cannot dereference this type
+ * check-error-end
+ */
diff --git a/validation/expand/constant-init-array.c b/validation/expand/constant-init-array.c
new file mode 100644
index 00000000..94949be5
--- /dev/null
+++ b/validation/expand/constant-init-array.c
@@ -0,0 +1,15 @@
+int test_array(int i)
+{
+ static const int a[3] = { 1, 2, 3, };
+
+ return a[1];
+}
+
+/*
+ * check-name: constant-init-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: phisrc\\..*return.*\\$2
+ * check-output-contains: load\\.
+ */
diff --git a/validation/expand/constant-init-nested-array.c b/validation/expand/constant-init-nested-array.c
new file mode 100644
index 00000000..0d50d955
--- /dev/null
+++ b/validation/expand/constant-init-nested-array.c
@@ -0,0 +1,15 @@
+int foo(void)
+{
+ int a[2][3] = {{0, 1, 2},{3, 4, 5}};
+ return a[1][2];
+}
+
+/*
+ * check-name: constant-init-nested-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$5
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/constant-init-nested-struct.c b/validation/expand/constant-init-nested-struct.c
new file mode 100644
index 00000000..f27de556
--- /dev/null
+++ b/validation/expand/constant-init-nested-struct.c
@@ -0,0 +1,23 @@
+struct s {
+ int a;
+ struct {
+ int b;
+ int c;
+ } s;
+};
+
+int foo(void)
+{
+ struct s s = {1, {2, 3}};
+ return s.s.c;
+}
+
+/*
+ * check-name: constant-init-nested-struct
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$3
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/constant-init-string.c b/validation/expand/constant-init-string.c
new file mode 100644
index 00000000..42ae9bd3
--- /dev/null
+++ b/validation/expand/constant-init-string.c
@@ -0,0 +1,15 @@
+char foo(void)
+{
+ static const char s[] = "abc?";
+ return s[3];
+}
+
+/*
+ * check-name: constant-init-nested-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*\\$63
+ * check-output-pattern(0,1): load\\.
+ */
diff --git a/validation/expand/constant-union-flt2int.c b/validation/expand/constant-union-flt2int.c
new file mode 100644
index 00000000..5e25b592
--- /dev/null
+++ b/validation/expand/constant-union-flt2int.c
@@ -0,0 +1,20 @@
+union u {
+ int i;
+ float f;
+};
+
+static int foo(void)
+{
+ union u u = { .f = 0.123 };
+ return u.i;
+}
+
+/*
+ * check-name: constant-union-float-to-int
+ * check description: must not infer the int value from the float
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): setfval\\.
+ * check-output-pattern(1): load\\.
+ */
diff --git a/validation/expand/constant-union-int2flt.c b/validation/expand/constant-union-int2flt.c
new file mode 100644
index 00000000..16ce1c6f
--- /dev/null
+++ b/validation/expand/constant-union-int2flt.c
@@ -0,0 +1,19 @@
+union u {
+ int i;
+ float f;
+};
+
+static float foo(void)
+{
+ union u u = { .i = 3 };
+ return u.f;
+}
+
+/*
+ * check-name: constant-union-int-to-float
+ * check description: must not infer the float value from the int
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-pattern(1): load\\.
+ */
diff --git a/validation/bug-expand-union0.c b/validation/expand/constant-union-size.c
index dd6d60c3..8a16bf3e 100644
--- a/validation/bug-expand-union0.c
+++ b/validation/expand/constant-union-size.c
@@ -10,10 +10,9 @@ static int foo(void)
}
/*
- * check-name: bug-expand-union
- * check description: must not infer the value from the float
- * check-command: test-linearize $file
- * check-known-to-fail
+ * check-name: constant-union-size
+ * check description: the size of the initializer doesn't match
+ * check-command: test-linearize -fdump-ir $file
*
* check-output-ignore
* check-output-contains: load\\.
diff --git a/validation/expand/cost-deref-nested.c b/validation/expand/cost-deref-nested.c
new file mode 100644
index 00000000..d6b62396
--- /dev/null
+++ b/validation/expand/cost-deref-nested.c
@@ -0,0 +1,20 @@
+struct s {
+ struct {
+ int u, v;
+ } a, b;
+};
+
+static const struct s s;
+
+static int foo(int c)
+{
+ return c && s.b.v;
+}
+
+/*
+ * check-name: cost-deref-nested
+ * check-command: test-linearize -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-excludes: cbr
+ */
diff --git a/validation/expand/default-init-array.c b/validation/expand/default-init-array.c
new file mode 100644
index 00000000..b372ea09
--- /dev/null
+++ b/validation/expand/default-init-array.c
@@ -0,0 +1,16 @@
+int test_array(int i)
+{
+ static const int a[3] = { [0] = 1, [2] = 3, };
+
+ return a[1];
+}
+
+/*
+ * check-name: default-init-array
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*return.*\\$0
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/default-init-struct.c b/validation/expand/default-init-struct.c
new file mode 100644
index 00000000..085dd2d6
--- /dev/null
+++ b/validation/expand/default-init-struct.c
@@ -0,0 +1,22 @@
+struct s {
+ int a;
+ int b;
+ int c;
+};
+
+
+int test_struct(void)
+{
+ struct s s = { .a = 1, .c = 3, };
+
+ return s.b;
+}
+
+/*
+ * check-name: default-init-struct
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ *
+ * check-output-ignore
+ * check-output-contains: phisrc\\..*return.*\\$0
+ * check-output-excludes: load\\.
+ */
diff --git a/validation/expand/union-cast.c b/validation/expand/union-cast.c
new file mode 100644
index 00000000..a28d01f2
--- /dev/null
+++ b/validation/expand/union-cast.c
@@ -0,0 +1,27 @@
+union u {
+ int i;
+ struct s {
+ int a;
+ } s;
+};
+
+int foo(void)
+{
+ struct s s = { 3 };
+ union u u = (union u)s;
+ return u.s.a;
+}
+
+/*
+ * check-name: union-cast
+ * check-command: test-linearize -Wno-decl -fdump-ir $file
+ * check-known-to-fail
+ *
+ * check-output-ignore
+ * check-output-excludes: load\\.
+ *
+ * check-error-start
+union-cast.c:11:22: warning: cast to non-scalar
+union-cast.c:11:22: warning: cast from non-scalar
+ * check-error-end
+ */
diff --git a/validation/function-redecl.c b/validation/function-redecl.c
index 475f18e7..03151359 100644
--- a/validation/function-redecl.c
+++ b/validation/function-redecl.c
@@ -48,15 +48,45 @@ void arg_vararg(int a, ...) { } /* check-should-fail */
* check-name: function-redecl
*
* check-error-start
-function-redecl.c:5:6: error: symbol 'ret_type' redeclared with different type (originally declared at function-redecl.c:4) - different base types
-function-redecl.c:9:11: error: symbol 'ret_const' redeclared with different type (originally declared at function-redecl.c:8) - different modifiers
-function-redecl.c:13:13: error: symbol 'ret_as' redeclared with different type (originally declared at function-redecl.c:12) - different address spaces
-function-redecl.c:17:12: error: symbol 'ret_mod' redeclared with different type (originally declared at function-redecl.c:16) - different modifiers
-function-redecl.c:21:6: error: symbol 'arg_type' redeclared with different type (originally declared at function-redecl.c:20) - incompatible argument 1 (different base types)
-function-redecl.c:29:6: error: symbol 'arg_as' redeclared with different type (originally declared at function-redecl.c:28) - incompatible argument 1 (different address spaces)
-function-redecl.c:33:6: error: symbol 'arg_mod' redeclared with different type (originally declared at function-redecl.c:32) - incompatible argument 1 (different modifiers)
-function-redecl.c:37:6: error: symbol 'arg_more_arg' redeclared with different type (originally declared at function-redecl.c:36) - different argument counts
-function-redecl.c:41:6: error: symbol 'arg_less_arg' redeclared with different type (originally declared at function-redecl.c:40) - different argument counts
-function-redecl.c:45:6: error: symbol 'arg_vararg' redeclared with different type (originally declared at function-redecl.c:44) - incompatible variadic arguments
+function-redecl.c:5:6: error: symbol 'ret_type' redeclared with different type (different base types):
+function-redecl.c:5:6: void extern [addressable] [toplevel] ret_type( ... )
+function-redecl.c:4:5: note: previously declared as:
+function-redecl.c:4:5: int extern [signed] [addressable] [toplevel] ret_type( ... )
+function-redecl.c:9:11: error: symbol 'ret_const' redeclared with different type (different modifiers):
+function-redecl.c:9:11: int extern const [signed] [addressable] [toplevel] ret_const( ... )
+function-redecl.c:8:5: note: previously declared as:
+function-redecl.c:8:5: int extern [signed] [addressable] [toplevel] ret_const( ... )
+function-redecl.c:13:13: error: symbol 'ret_as' redeclared with different type (different address spaces):
+function-redecl.c:13:13: void <asn:1> *extern [addressable] [toplevel] ret_as( ... )
+function-redecl.c:12:6: note: previously declared as:
+function-redecl.c:12:6: void *extern [addressable] [toplevel] ret_as( ... )
+function-redecl.c:17:12: error: symbol 'ret_mod' redeclared with different type (different modifiers):
+function-redecl.c:17:12: void const *extern [addressable] [toplevel] ret_mod( ... )
+function-redecl.c:16:6: note: previously declared as:
+function-redecl.c:16:6: void *extern [addressable] [toplevel] ret_mod( ... )
+function-redecl.c:21:6: error: symbol 'arg_type' redeclared with different type (incompatible argument 1 (different base types)):
+function-redecl.c:21:6: void extern [addressable] [toplevel] arg_type( ... )
+function-redecl.c:20:6: note: previously declared as:
+function-redecl.c:20:6: void extern [addressable] [toplevel] arg_type( ... )
+function-redecl.c:29:6: error: symbol 'arg_as' redeclared with different type (incompatible argument 1 (different address spaces)):
+function-redecl.c:29:6: void extern [addressable] [toplevel] arg_as( ... )
+function-redecl.c:28:6: note: previously declared as:
+function-redecl.c:28:6: void extern [addressable] [toplevel] arg_as( ... )
+function-redecl.c:33:6: error: symbol 'arg_mod' redeclared with different type (incompatible argument 1 (different modifiers)):
+function-redecl.c:33:6: void extern [addressable] [toplevel] arg_mod( ... )
+function-redecl.c:32:6: note: previously declared as:
+function-redecl.c:32:6: void extern [addressable] [toplevel] arg_mod( ... )
+function-redecl.c:37:6: error: symbol 'arg_more_arg' redeclared with different type (different argument counts):
+function-redecl.c:37:6: void extern [addressable] [toplevel] arg_more_arg( ... )
+function-redecl.c:36:6: note: previously declared as:
+function-redecl.c:36:6: void extern [addressable] [toplevel] arg_more_arg( ... )
+function-redecl.c:41:6: error: symbol 'arg_less_arg' redeclared with different type (different argument counts):
+function-redecl.c:41:6: void extern [addressable] [toplevel] arg_less_arg( ... )
+function-redecl.c:40:6: note: previously declared as:
+function-redecl.c:40:6: void extern [addressable] [toplevel] arg_less_arg( ... )
+function-redecl.c:45:6: error: symbol 'arg_vararg' redeclared with different type (incompatible variadic arguments):
+function-redecl.c:45:6: void extern [addressable] [toplevel] arg_vararg( ... )
+function-redecl.c:44:6: note: previously declared as:
+function-redecl.c:44:6: void extern [addressable] [toplevel] arg_vararg( ... )
* check-error-end
*/
diff --git a/validation/bug-expand-union1.c b/validation/memops/type-punning-flt2int.c
index 582a1f4f..fadaf687 100644
--- a/validation/bug-expand-union1.c
+++ b/validation/memops/type-punning-flt2int.c
@@ -10,10 +10,9 @@ static int foo(void)
}
/*
- * check-name: bug-expand-union
- * check description: must not infer the value from the float
+ * check-name: type-punning-float-to-int
+ * check description: must not infer the int value from the float
* check-command: test-linearize $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-contains: load\\.
diff --git a/validation/memops/type-punning-int2flt.c b/validation/memops/type-punning-int2flt.c
new file mode 100644
index 00000000..061b7423
--- /dev/null
+++ b/validation/memops/type-punning-int2flt.c
@@ -0,0 +1,19 @@
+union u {
+ int i;
+ float f;
+};
+
+static float foo(void)
+{
+ union u u = { .i = 3 };
+ return u.f;
+}
+
+/*
+ * check-name: type-punning-int-to-float
+ * check description: must not infer the float value from the int
+ * check-command: test-linearize $file
+ *
+ * check-output-ignore
+ * check-output-contains: load\\.
+ */
diff --git a/validation/nocast.c b/validation/nocast.c
index 6c5da968..2113227c 100644
--- a/validation/nocast.c
+++ b/validation/nocast.c
@@ -26,8 +26,8 @@ static ulong_nc_t good_deref(ulong_nc_t *t)
/* assign value */
static ulong_nc_t t;
-static ulong_nc_t good_assign_self = t;
-static unsigned long good_assign_sametype = t;
+
+
/* assign pointer */
static ulong_nc_t *good_ptr = &t;
@@ -150,6 +150,12 @@ static unsigned long bad_fromcast(ulong_nc_t v)
return (unsigned long) v;
}
+static void assign_value(void)
+{
+ ulong_nc_t good_assign_self = t;
+ unsigned long good_assign_sametype = t;
+}
+
/*
* check-name: nocast.c
*
diff --git a/validation/restrict.c b/validation/restrict.c
index 92bfdae8..d7cd8ad9 100644
--- a/validation/restrict.c
+++ b/validation/restrict.c
@@ -66,11 +66,17 @@ void baz(void)
/*
* check-name: restrict qualifier
- * check-command: sparse -Wno-decl $file;
+ * check-command: sparse -Wno-decl $file
*
* check-error-start
-restrict.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at restrict.c:3) - incompatible argument 1 (different modifiers)
-restrict.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at restrict.c:4) - incompatible argument 1 (different modifiers)
+restrict.c:11:6: error: symbol 'f02' redeclared with different type (incompatible argument 1 (different modifiers)):
+restrict.c:11:6: void extern [addressable] [toplevel] f02( ... )
+restrict.c:3:6: note: previously declared as:
+restrict.c:3:6: void extern [addressable] [toplevel] f02( ... )
+restrict.c:12:6: error: symbol 'f03' redeclared with different type (incompatible argument 1 (different modifiers)):
+restrict.c:12:6: void extern [addressable] [toplevel] f03( ... )
+restrict.c:4:6: note: previously declared as:
+restrict.c:4:6: void extern [addressable] [toplevel] f03( ... )
restrict.c:33:13: warning: incorrect type in assignment (different modifiers)
restrict.c:33:13: expected void **extern [assigned] pup
restrict.c:33:13: got void *const *
diff --git a/validation/typedef-redef.c b/validation/typedef-redef.c
index 3a60a773..f90f266a 100644
--- a/validation/typedef-redef.c
+++ b/validation/typedef-redef.c
@@ -8,6 +8,9 @@ typedef long ko_t;
* check-name: typedef-redef
*
* check-error-start
-typedef-redef.c:5:14: error: symbol 'ko_t' redeclared with different type (originally declared at typedef-redef.c:4) - different type sizes
+typedef-redef.c:5:14: error: symbol 'ko_t' redeclared with different type (different type sizes):
+typedef-redef.c:5:14: long [usertype] ko_t
+typedef-redef.c:4:14: note: previously declared as:
+typedef-redef.c:4:14: int [usertype] ko_t
* check-error-end
*/