aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/TODO.md29
-rw-r--r--Documentation/release-notes/index.rst1
-rw-r--r--Documentation/release-notes/v0.6.3.rst57
-rw-r--r--Makefile4
-rw-r--r--builtin.c114
-rw-r--r--evaluate.c76
-rw-r--r--lib.h2
-rw-r--r--opcode.def2
-rw-r--r--options.c8
-rw-r--r--options.h4
-rw-r--r--predefine.c7
-rw-r--r--simplify.c6
-rw-r--r--sparse.130
-rw-r--r--symbol.c73
-rw-r--r--symbol.h27
-rw-r--r--target-x86.c8
-rw-r--r--validation/builtin-arith.c31
-rw-r--r--validation/builtin-atomic-clear.c15
-rw-r--r--validation/builtin-sync-fetch.c24
-rw-r--r--validation/crash-undef-in-parens.c9
-rw-r--r--validation/flex-array-align.c18
-rw-r--r--validation/flex-array-array.c15
-rw-r--r--validation/flex-array-error.c26
-rw-r--r--validation/flex-array-nested.c29
-rw-r--r--validation/flex-array-sizeof.c18
-rw-r--r--validation/flex-array-union-array-no.c9
-rw-r--r--validation/flex-array-union-array-yes.c11
-rw-r--r--validation/flex-array-union-array.h11
-rw-r--r--validation/linear/bool-cast-lp32.c1
-rw-r--r--validation/optim/canonical-mul.c2
-rw-r--r--validation/usual-conv-lp32.c11
31 files changed, 561 insertions, 117 deletions
diff --git a/Documentation/TODO.md b/Documentation/TODO.md
index e2043e48..4dc9e63a 100644
--- a/Documentation/TODO.md
+++ b/Documentation/TODO.md
@@ -4,13 +4,13 @@ TODO
Essential
---------
* SSA is broken by simplify_loads() & branches rewriting/simplification
-* attributes of struct, union & enums are ignored (and possibly in other
- cases too).
-* add support for bitwise enums
+* attributes of struct, union & enums are ignored (and maybe others too).
+ This requires correct support for __packed which itself needs partial
+ and unaligned loads & stores (wip)
+* add support for bitwise enums (wip)
Documentation
-------------
-* document the extensions
* document the API
* document the limitations of modifying ptrlists during list walking
* document the data structures
@@ -27,7 +27,7 @@ Core
Testsuite
---------
-* there are more than 50 failing tests. They should be fixed
+* there are 60 failing tests. They should be fixed
(but most are non-trivial to fix).
Misc
@@ -36,15 +36,26 @@ Misc
* parse __attribute_((fallthrough))
* add support for format(printf()) (WIP by Ben Dooks)
* make use of UNDEFs (issues warnings, simplification, ... ?)
-* add a pass to inline small functions during simplification.
+* make memory accesses more explicit: add EXPR_ACCESS (wip)
+* it would be nice to do our own parsing of floating point (wip)
+* some header files needed for crypto/ need __vector or __fp16
+* some even need __complex
Optimization
------------
+* a lot of small simplifications are waiting to be upstreamed
+* the domtree need to be rebuilt (or updated)
+* critical edges need to be split
* the current way of doing CSE uses a lot of time
* add SSA based DCE
* add SSA based PRE
* Add SSA based SCCP
+* add a pass to inline small functions during simplification.
* use better/more systematic use of internal verification framework
+* tracking of operands size should be improved (WIP)
+* OP_INLINE is sometimes in the way
+* would be nice to strictly separate phases that don't changes the
+ CFG and thus the dominance tree.
IR
--
@@ -60,13 +71,15 @@ LLVM
Internal backends
-----------------
-* add some basic register allocation
+* it would be nice the upstream the code generator
* add a pass to transform 3-addresses code to 2-addresses
+* add some basic register allocation
+* add a pass to order the BBs and changes 2-ways CBR into one-way branches
* what can be done for x86?
+* add support to add constraints in the MD rules
Longer term/to investigate
--------------------------
-* better architecture handling than current machine.h + target.c
* attributes are represented as ctypes's alignment, modifiers & contexts
but plenty of attributes doesn't fit, for example they need arguments.
* format(printf, ...),
diff --git a/Documentation/release-notes/index.rst b/Documentation/release-notes/index.rst
index aa026653..f886470e 100644
--- a/Documentation/release-notes/index.rst
+++ b/Documentation/release-notes/index.rst
@@ -5,6 +5,7 @@ Release Notes
.. toctree::
:maxdepth: 1
+ v0.6.3
v0.6.2
v0.6.1
v0.6.0
diff --git a/Documentation/release-notes/v0.6.3.rst b/Documentation/release-notes/v0.6.3.rst
index 1aae742e..7ec59eff 100644
--- a/Documentation/release-notes/v0.6.3.rst
+++ b/Documentation/release-notes/v0.6.3.rst
@@ -1,5 +1,56 @@
-v0.6.3 (2020-xx-xy)
+v0.6.3 (2020-10-17)
===================
-* Changes in warnings:
- "warning: cast to union type" [disable with -Wno-union-cast]
+Bug fixes:
+ * fix missing inlining of _Generic expression
+ * fix evaluation error with assignment of qualified arrays
+ * delay 'empty character constant' warning to phase 5
+ * simplify & fix parsing of array declarators
+ * accept whitespace after option -U
+ * teach dissect about _Generic
+ * reset locale after gtk_init() to workaround problems with strtold()
+ * fix linearization of shift-assign
+ * force to 0 expressions which are erroneously non-constant
+ * fix evaluate_ptr_add() when sizeof(offset) != sizeof(pointer)
+ * fix access to defining instruction in simplify_unop()
+ * fix evaluation of pointer to bool conversions
+ * fix usual conversion of integers
+ * fix null pointer deref on return expression with invalid type
+
+New features:
+ * add support for arch specific asm constraints
+ * add memory asm constraint for PPC & S390
+ * prepend diagnostics with source's path and include chain
+ * add support for h8300, microblaze, nds32, openrisc, sh & xtensa
+ * add support for '-march=....' and use it for riscv
+ * add an option to specify the OS: --os=$OS
+ * add predefines for OS identification
+ * add predefines for __INT_LEAST${N}_TYPE__ & __INT_FAST${N}_TYPE__
+ * document the sparse's extensions
+ * sindex/semind: allow indexing outside the project tree
+ * rename tool 'sindex' to 'semind'
+ * add builtin support for __sync_{bool,val}_compare_and_swap()
+ * add support for wide strings
+ * union-cast: teach sparse about union casts
+ * add support for a new instruction: OP_FMADD
+ * add various warnings for dangerous usage of flexible array members
+ * add builtin support for __builtin_ia32_pause()
+
+Misc changes:
+ * cleanup the handling of options flags
+ * avoid multiple warnings when inlining undeclared calls
+ * small fixes for alpha, arm, nios2, ppc, sparc & x86
+ * add missing predefines for endianness on arm, arm64, mips
+ * add various missing arch-specific predefines
+ * add the predefines '__cdecl', ... on cygwin
+ * warn on empty assignments & initializations
+ * reorganize the keyword parsing table
+ * the message in _Static_assert() is now optional (C2x)
+ * small fixes & improvement to the [online] documentation
+ * allow [*] in array declarators
+ * do not accept comma expressions in array declarator
+ * simplify parsing of attributes & storage class
+ * bad-shift: wait dead code elimination to warn about bad shifts
+ * fix is_scalar_type(): fouled types are scalars too
+ * better support for linearization of builtins
+ * remove definition of removed OP_{AND,OR}_BOOL
diff --git a/Makefile b/Makefile
index 09726ebb..31366446 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.6.2
+VERSION=0.6.3
########################################################################
# The following variables can be overwritten from the command line
@@ -273,7 +273,7 @@ version.h: FORCE
check: all
$(Q)cd validation && ./test-suite
-validation/%: $(PROGRAMS)
+validation/%: $(PROGRAMS) FORCE
$(Q)validation/test-suite $*
diff --git a/builtin.c b/builtin.c
index 26b612dc..acc49871 100644
--- a/builtin.c
+++ b/builtin.c
@@ -31,6 +31,14 @@
#include "compat/bswap.h"
#include <stdarg.h>
+#define dyntype incomplete_ctype
+static bool is_dynamic_type(struct symbol *t)
+{
+ if (t->type == SYM_NODE)
+ t = t->ctype.base_type;
+ return t == &dyntype;
+}
+
static int evaluate_to_int_const_expr(struct expression *expr)
{
expr->ctype = &int_ctype;
@@ -83,6 +91,13 @@ error:
return 0;
}
+static int args_prototype(struct expression *expr)
+{
+ struct symbol *fntype = expr->fn->ctype->ctype.base_type;
+ int n = symbol_list_size(fntype->arguments);
+ return eval_args(expr, n);
+}
+
static int args_triadic(struct expression *expr)
{
return eval_args(expr, 3);
@@ -355,29 +370,32 @@ static struct symbol_op overflow_p_op = {
};
-static int eval_sync_compare_and_swap(struct expression *expr)
+static int eval_atomic_common(struct expression *expr)
{
+ struct symbol *fntype = expr->fn->ctype->ctype.base_type;
struct symbol_list *types = NULL;
struct symbol *ctype = NULL;
+ struct symbol *t;
struct expression *arg;
int n = 0;
- /* the first arg is a pointer type; we'd already verified that */
+ // The number of arguments has already be verified.
+ // The first arg must be a pointer to an integral type.
+ PREPARE_PTR_LIST(fntype->arguments, t);
FOR_EACH_PTR(expr->args, arg) {
- struct symbol *t = arg->ctype;
+ struct symbol *ptrtype = NULL;
- if (!t)
- return 0;
-
- // 2nd & 3rd args must be a basic integer type or a pointer
- // 1st arg must be a pointer to such a type.
if (++n == 1) {
+ t = arg->ctype;
+ if (!t)
+ return 0;
if (t->type == SYM_NODE)
t = t->ctype.base_type;
if (!t)
return 0;
if (t->type != SYM_PTR)
goto err;
+ ptrtype = t;
t = t->ctype.base_type;
if (!t)
return 0;
@@ -388,13 +406,18 @@ static int eval_sync_compare_and_swap(struct expression *expr)
if (t->type != SYM_PTR && t->ctype.base_type != &int_type)
goto err;
ctype = t;
- add_ptr_list(&types, arg->ctype);
- } else {
- add_ptr_list(&types, ctype);
+ t = ptrtype;
+ } else if (is_dynamic_type(t)) {
+ t = ctype;
+ } else if (t == &ptr_ctype) {
+ t = ptrtype;
}
+ add_ptr_list(&types, t);
+ NEXT_PTR_LIST(t);
} END_FOR_EACH_PTR(arg);
+ FINISH_PTR_LIST(t);
- if (!expr->ctype) // __sync_val_compare_and_swap()
+ if (!expr->ctype) // set the return type, if needed
expr->ctype = ctype;
return evaluate_arguments(types, expr->args);
@@ -405,9 +428,9 @@ err:
return 0;
}
-static struct symbol_op sync_compare_and_swap_op = {
- .args = args_triadic,
- .evaluate = eval_sync_compare_and_swap,
+static struct symbol_op atomic_op = {
+ .args = args_prototype,
+ .evaluate = eval_atomic_common,
};
@@ -457,6 +480,33 @@ static void declare_builtins(int stream, const struct builtin_fn tbl[])
static const struct builtin_fn builtins_common[] = {
#define size_t_ctype &size_t_alias
#define va_list_ctype &ptr_ctype
+#define vol_ptr &volatile_ptr_ctype
+ { "__atomic_add_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_always_lock_free", &bool_ctype, 0, { size_t_ctype, vol_ptr }},
+ { "__atomic_and_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_clear", &void_ctype, 0, { &volatile_bool_ptr_ctype, &int_ctype }},
+ { "__atomic_compare_exchange", &bool_ctype, 0, { vol_ptr, &ptr_ctype, &ptr_ctype, &bool_ctype, &int_ctype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_compare_exchange_n", &bool_ctype, 0, { vol_ptr, &ptr_ctype, &dyntype, &bool_ctype, &int_ctype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_exchange", &void_ctype, 0, { vol_ptr, &ptr_ctype, &ptr_ctype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_exchange_n", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_add", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_and", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_nand",NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_or", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_sub", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_fetch_xor", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_is_lock_free", &bool_ctype, 0, { size_t_ctype, vol_ptr }},
+ { "__atomic_load", &void_ctype, 0, { vol_ptr, &ptr_ctype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_load_n", NULL, 0, { vol_ptr, &int_ctype }, .op = &atomic_op },
+ { "__atomic_nand_fetch",NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_or_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_signal_fence", &void_ctype, 0, { &int_ctype }},
+ { "__atomic_store", &void_ctype, 0, { vol_ptr, &ptr_ctype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_store_n", &void_ctype, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_sub_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
+ { "__atomic_test_and_set", &bool_ctype, 0, { vol_ptr, &int_ctype }},
+ { "__atomic_thread_fence", &void_ctype, 0, { &int_ctype }},
+ { "__atomic_xor_fetch", NULL, 0, { vol_ptr, &dyntype, &int_ctype }, .op = &atomic_op },
{ "__builtin_choose_expr", NULL, 1, .op = &choose_op },
{ "__builtin_constant_p", NULL, 1, .op = &constant_p_op },
{ "__builtin_expect", &long_ctype, 0, { &long_ctype ,&long_ctype }, .op = &expect_op },
@@ -605,23 +655,23 @@ static const struct builtin_fn builtins_common[] = {
{ "__builtin___vsnprintf_chk", &int_ctype, 0, { &string_ctype, size_t_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype }},
{ "__builtin___vsprintf_chk", &int_ctype, 0, { &string_ctype, &int_ctype, size_t_ctype, &const_string_ctype, va_list_ctype }},
- { "__sync_add_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_and_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_bool_compare_and_swap", &bool_ctype, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op},
- { "__sync_fetch_and_add", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_fetch_and_and", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_fetch_and_nand", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_fetch_and_or", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_fetch_and_sub", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_fetch_and_xor", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_lock_release", &void_ctype, 1, { &ptr_ctype }},
- { "__sync_lock_test_and_set", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_nand_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_or_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_sub_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_synchronize", &void_ctype, 0 },
- { "__sync_val_compare_and_swap", NULL, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op },
- { "__sync_xor_and_fetch", &int_ctype, 1, { &ptr_ctype }},
+ { "__sync_add_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_and_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_bool_compare_and_swap", &bool_ctype, 1, { vol_ptr, &dyntype, &dyntype }, .op = &atomic_op},
+ { "__sync_fetch_and_add", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_fetch_and_and", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_fetch_and_nand", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_fetch_and_or", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_fetch_and_sub", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_fetch_and_xor", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_lock_release", &void_ctype, 1, { vol_ptr }, .op = &atomic_op },
+ { "__sync_lock_test_and_set", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_nand_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_or_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_sub_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
+ { "__sync_synchronize", &void_ctype, 1 },
+ { "__sync_val_compare_and_swap", NULL, 1, { vol_ptr, &dyntype, &dyntype }, .op = &atomic_op },
+ { "__sync_xor_and_fetch", NULL, 1, { vol_ptr, &dyntype }, .op = &atomic_op },
{ }
};
diff --git a/evaluate.c b/evaluate.c
index c1ef348a..43a61169 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -164,49 +164,52 @@ static inline struct symbol *integer_promotion(struct symbol *type)
}
/*
- * integer part of usual arithmetic conversions:
- * integer promotions are applied
- * if left and right are identical, we are done
- * if signedness is the same, convert one with lower rank
- * unless unsigned argument has rank lower than signed one, convert the
- * signed one.
- * if signed argument is bigger than unsigned one, convert the unsigned.
- * otherwise, convert signed.
- *
- * Leaving aside the integer promotions, that is equivalent to
- * if identical, don't convert
- * if left is bigger than right, convert right
- * if right is bigger than left, convert right
- * otherwise, if signedness is the same, convert one with lower rank
- * otherwise convert the signed one.
+ * After integer promotons:
+ * If both types are the same
+ * -> no conversion needed
+ * If the types have the same signedness (their rank must be different)
+ * -> convert to the type of the highest rank
+ * If rank(unsigned type) >= rank(signed type)
+ * -> convert to the unsigned type
+ * If size(signed type) > size(unsigned type)
+ * -> convert to the signed type
+ * Otherwise
+ * -> convert to the unsigned type corresponding to the signed type.
*/
static struct symbol *bigger_int_type(struct symbol *left, struct symbol *right)
{
+ static struct symbol *unsigned_types[] = {
+ [0] = &uint_ctype,
+ [1] = &ulong_ctype,
+ [2] = &ullong_ctype,
+ [3] = &uint128_ctype,
+ };
unsigned long lmod, rmod;
+ struct symbol *stype, *utype;
left = integer_promotion(left);
right = integer_promotion(right);
if (left == right)
- goto left;
-
- if (left->bit_size > right->bit_size)
- goto left;
-
- if (right->bit_size > left->bit_size)
- goto right;
+ return left;
lmod = left->ctype.modifiers;
rmod = right->ctype.modifiers;
- if ((lmod ^ rmod) & MOD_UNSIGNED) {
- if (lmod & MOD_UNSIGNED)
- goto left;
- } else if (left->rank > right->rank)
- goto left;
-right:
- left = right;
-left:
- return left;
+ if (((lmod ^ rmod) & MOD_UNSIGNED) == 0)
+ return (left->rank > right->rank) ? left : right;
+ if (lmod & MOD_UNSIGNED) {
+ utype = left;
+ stype = right;
+ } else {
+ stype = left;
+ utype = right;
+ }
+ if (utype->rank >= stype->rank)
+ return utype;
+ if (stype->bit_size > utype->bit_size)
+ return stype;
+ utype = unsigned_types[stype->rank];
+ return utype;
}
static int same_cast_type(struct symbol *orig, struct symbol *new)
@@ -1784,6 +1787,8 @@ static struct symbol *degenerate(struct expression *expr)
expression_error(expr, "strange non-value function or array");
return &bad_ctype;
}
+ if (ctype->builtin)
+ sparse_error(expr->pos, "taking the address of built-in function '%s'", show_ident(ctype->ident));
*expr = *expr->unop;
ctype = create_pointer(expr, ctype, 1);
expr->ctype = ctype;
@@ -1804,6 +1809,8 @@ static struct symbol *evaluate_addressof(struct expression *expr)
return NULL;
}
ctype = op->ctype;
+ if (ctype->builtin)
+ sparse_error(expr->pos, "taking the address of built-in function '%s'", show_ident(ctype->ident));
*expr = *op->unop;
mark_addressable(expr);
@@ -2253,6 +2260,9 @@ static struct symbol *evaluate_sizeof(struct expression *expr)
size = bits_in_char;
}
+ if (has_flexible_array(type) && Wflexible_array_sizeof)
+ warning(expr->pos, "using sizeof on a flexible structure");
+
if (is_array_type(type) && size < 0) { // VLA, 1-dimension only
struct expression *base, *size;
struct symbol *base_type;
@@ -2883,6 +2893,8 @@ static struct symbol *cast_to_bool(struct expression *expr)
return NULL;
zero = alloc_const_expression(expr->pos, 0);
+ if (oclass & TYPE_PTR)
+ zero->ctype = otype;
expr->op = SPECIAL_NOTEQUAL;
ctype = usual_conversions(expr->op, old, zero,
oclass, TYPE_NUM, otype, zero->ctype);
@@ -3603,7 +3615,7 @@ static struct symbol *evaluate_return_expression(struct statement *stmt)
fntype = current_fn->ctype.base_type;
rettype = fntype->ctype.base_type;
if (!rettype || rettype == &void_ctype) {
- if (expr && !is_void_type(expr->ctype))
+ if (expr && expr->ctype && !is_void_type(expr->ctype))
expression_error(expr, "return expression in %s function", rettype?"void":"typeless");
if (expr && Wreturn_void)
warning(stmt->pos, "returning void-valued expression");
diff --git a/lib.h b/lib.h
index b35debc8..0b1d4492 100644
--- a/lib.h
+++ b/lib.h
@@ -44,7 +44,7 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
-#ifndef PATH_MAX
+#ifdef __gnu_hurd__
#define PATH_MAX 4096 // Hurd doesn't define this
#endif
diff --git a/opcode.def b/opcode.def
index 7959efaf..1401d988 100644
--- a/opcode.def
+++ b/opcode.def
@@ -33,8 +33,6 @@ OPCODE(FMUL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
OPCODE(FDIV, BADOP, BADOP, BADOP, 2, OPF_TARGET)
/* Logical */
-OPCODE(AND_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
-OPCODE(OR_BOOL, BADOP, BADOP, BADOP, 2, OPF_TARGET)
OPCODE(AND, BADOP, BADOP, BADOP, 2, OPF_TARGET)
OPCODE(OR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
OPCODE(XOR, BADOP, BADOP, BADOP, 2, OPF_TARGET)
diff --git a/options.c b/options.c
index a12d2866..17da5f36 100644
--- a/options.c
+++ b/options.c
@@ -101,6 +101,10 @@ int Wdesignated_init = 1;
int Wdo_while = 0;
int Wenum_mismatch = 1;
int Wexternal_function_has_definition = 1;
+int Wflexible_array_array = 1;
+int Wflexible_array_nested = 0;
+int Wflexible_array_sizeof = 0;
+int Wflexible_array_union = 0;
int Wimplicit_int = 1;
int Winit_cstring = 0;
int Wint_to_pointer_cast = 1;
@@ -843,6 +847,10 @@ static const struct flag warnings[] = {
{ "do-while", &Wdo_while },
{ "enum-mismatch", &Wenum_mismatch },
{ "external-function-has-definition", &Wexternal_function_has_definition },
+ { "flexible-array-array", &Wflexible_array_array },
+ { "flexible-array-nested", &Wflexible_array_nested },
+ { "flexible-array-sizeof", &Wflexible_array_sizeof },
+ { "flexible-array-union", &Wflexible_array_union },
{ "implicit-int", &Wimplicit_int },
{ "init-cstring", &Winit_cstring },
{ "int-to-pointer-cast", &Wint_to_pointer_cast },
diff --git a/options.h b/options.h
index 8e3071a7..0aec8764 100644
--- a/options.h
+++ b/options.h
@@ -100,6 +100,10 @@ extern int Wdesignated_init;
extern int Wdo_while;
extern int Wenum_mismatch;
extern int Wexternal_function_has_definition;
+extern int Wflexible_array_array;
+extern int Wflexible_array_nested;
+extern int Wflexible_array_sizeof;
+extern int Wflexible_array_union;
extern int Wimplicit_int;
extern int Winit_cstring;
extern int Wint_to_pointer_cast;
diff --git a/predefine.c b/predefine.c
index f898cdfa..98e38a04 100644
--- a/predefine.c
+++ b/predefine.c
@@ -179,6 +179,13 @@ void predefined_macros(void)
if (arch_target->has_int128)
predefined_sizeof("INT128", "", 128);
+ predefine("__ATOMIC_RELAXED", 0, "0");
+ predefine("__ATOMIC_CONSUME", 0, "1");
+ predefine("__ATOMIC_ACQUIRE", 0, "3");
+ predefine("__ATOMIC_RELEASE", 0, "4");
+ predefine("__ATOMIC_ACQ_REL", 0, "7");
+ predefine("__ATOMIC_SEQ_CST", 0, "8");
+
predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234");
predefine("__ORDER_BIG_ENDIAN__", 1, "4321");
predefine("__ORDER_PDP_ENDIAN__", 1, "3412");
diff --git a/simplify.c b/simplify.c
index 76c05588..15452a58 100644
--- a/simplify.c
+++ b/simplify.c
@@ -1311,13 +1311,11 @@ static int simplify_unop(struct instruction *insn)
struct instruction *def;
case OP_NOT:
- def = insn->src->def;
- if (def && def->opcode == OP_NOT)
+ if (DEF_OPCODE(def, insn->src) == OP_NOT)
return replace_with_pseudo(insn, def->src);
break;
case OP_NEG:
- def = insn->src->def;
- if (def && def->opcode == OP_NEG)
+ if (DEF_OPCODE(def, insn->src) == OP_NEG)
return replace_with_pseudo(insn, def->src);
break;
default:
diff --git a/sparse.1 b/sparse.1
index 2a8eb124..430b3710 100644
--- a/sparse.1
+++ b/sparse.1
@@ -257,6 +257,36 @@ Sparse issues these warnings by default. To turn them off, use
\fB\-Wno\-external\-function\-has\-definition\fR.
.
.TP
+.B -Wflexible-array-array
+Warn about arrays of structures containing a flexible array.
+
+Sparse issues these warnings by default. To turn them off, use
+\fB-Wno-flexible-array-array\fR.
+.
+.TP
+.B -Wflexible-array-nested
+Warn about structures containing a flexible array being contained into
+another structure, union or array.
+
+Sparse does not issue these warnings by default.
+.
+.TP
+.B -Wflexible-array-sizeof
+Warn about using the sizeof operator on a structure containing a flexible array,
+possibly recursively.
+
+Sparse does not issue these warnings by default.
+.
+.TP
+.B -Wflexible-array-union
+Enable the warnings regarding flexible arrays and unions.
+To have any effect, at least one of \fB-Wflexible-array-array\fR,
+\fB-Wflexible-array-nested\fR or \fB-Wflexible-array-sizeof\fR must also
+be enabled.
+
+Sparse does issue these warnings by default.
+.
+.TP
.B \-Winit\-cstring
Warn about initialization of a char array with a too long constant C string.
diff --git a/symbol.c b/symbol.c
index aaeb8c10..1a083fb8 100644
--- a/symbol.c
+++ b/symbol.c
@@ -87,6 +87,8 @@ struct struct_union_info {
unsigned long max_align;
unsigned long bit_size;
int align_size;
+ char has_flex_array;
+ struct symbol *flex_array;
};
/*
@@ -94,13 +96,8 @@ struct struct_union_info {
*/
static void lay_out_union(struct symbol *sym, struct struct_union_info *info)
{
- examine_symbol_type(sym);
-
- // Unnamed bitfields do not affect alignment.
- if (sym->ident || !is_bitfield_type(sym)) {
- if (sym->ctype.alignment > info->max_align)
- info->max_align = sym->ctype.alignment;
- }
+ if (sym->bit_size < 0 && is_array_type(sym))
+ sparse_error(sym->pos, "flexible array member '%s' in a union", show_ident(sym->ident));
if (sym->bit_size > info->bit_size)
info->bit_size = sym->bit_size;
@@ -125,24 +122,18 @@ static void lay_out_struct(struct symbol *sym, struct struct_union_info *info)
unsigned long bit_size, align_bit_mask;
int base_size;
- examine_symbol_type(sym);
-
- // Unnamed bitfields do not affect alignment.
- if (sym->ident || !is_bitfield_type(sym)) {
- if (sym->ctype.alignment > info->max_align)
- info->max_align = sym->ctype.alignment;
- }
-
bit_size = info->bit_size;
base_size = sym->bit_size;
/*
- * Unsized arrays cause us to not align the resulting
- * structure size
+ * If the member is unsized, either it's a flexible array or
+ * it's invalid and a warning has already been issued.
*/
if (base_size < 0) {
- info->align_size = 0;
+ if (!is_array_type(sym))
+ return;
base_size = 0;
+ info->flex_array = sym;
}
align_bit_mask = bytes_to_bits(sym->ctype.alignment) - 1;
@@ -196,6 +187,20 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance
sparse_error(member->pos, "member '%s' has __auto_type", show_ident(member->ident));
member->ctype.base_type = &incomplete_ctype;
}
+ if (info.flex_array)
+ sparse_error(info.flex_array->pos, "flexible array member '%s' is not last", show_ident(info.flex_array->ident));
+ examine_symbol_type(member);
+
+ if (member->ctype.alignment > info.max_align) {
+ // Unnamed bitfields do not affect alignment.
+ if (member->ident || !is_bitfield_type(member))
+ info.max_align = member->ctype.alignment;
+ }
+
+ if (has_flexible_array(member))
+ info.has_flex_array = 1;
+ if (has_flexible_array(member) && Wflexible_array_nested)
+ warning(member->pos, "nested flexible array");
fn(member, &info);
} END_FOR_EACH_PTR(member);
@@ -206,6 +211,11 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance
bit_align = bytes_to_bits(sym->ctype.alignment)-1;
bit_size = (bit_size + bit_align) & ~bit_align;
}
+ if (info.flex_array) {
+ info.has_flex_array = 1;
+ }
+ if (info.has_flex_array && (!is_union_type(sym) || Wflexible_array_union))
+ sym->has_flex_array = 1;
sym->bit_size = bit_size;
return sym;
}
@@ -261,6 +271,8 @@ static struct symbol * examine_array_type(struct symbol *sym)
bit_size = -1;
}
}
+ if (has_flexible_array(base_type) && Wflexible_array_array)
+ warning(sym->pos, "array of flexible structures");
alignment = base_type->ctype.alignment;
if (!sym->ctype.alignment)
sym->ctype.alignment = alignment;
@@ -782,14 +794,19 @@ struct symbol bool_ctype, void_ctype, type_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
struct symbol autotype_ctype;
+struct symbol schar_ptr_ctype, short_ptr_ctype;
struct symbol int_ptr_ctype, uint_ptr_ctype;
struct symbol long_ptr_ctype, ulong_ptr_ctype;
struct symbol llong_ptr_ctype, ullong_ptr_ctype;
+struct symbol size_t_ptr_ctype, intmax_ptr_ctype, ptrdiff_ptr_ctype;
struct symbol float32_ctype, float32x_ctype;
struct symbol float64_ctype, float64x_ctype;
struct symbol float128_ctype;
struct symbol const_void_ctype, const_char_ctype;
struct symbol const_ptr_ctype, const_string_ctype;
+struct symbol const_wchar_ctype, const_wstring_ctype;
+struct symbol volatile_void_ctype, volatile_ptr_ctype;
+struct symbol volatile_bool_ctype, volatile_bool_ptr_ctype;
struct symbol zero_int;
@@ -876,17 +893,28 @@ static const struct ctype_declare {
{ &null_ctype, T_PTR(&void_ctype) },
{ &label_ctype, T_PTR(&void_ctype) },
{ &lazy_ptr_ctype, T_PTR(&void_ctype) },
+ { &schar_ptr_ctype, T_PTR(&schar_ctype) },
+ { &short_ptr_ctype, T_PTR(&short_ctype) },
{ &int_ptr_ctype, T_PTR(&int_ctype) },
{ &uint_ptr_ctype, T_PTR(&uint_ctype) },
{ &long_ptr_ctype, T_PTR(&long_ctype) },
{ &ulong_ptr_ctype, T_PTR(&ulong_ctype) },
{ &llong_ptr_ctype, T_PTR(&llong_ctype) },
{ &ullong_ptr_ctype, T_PTR(&ullong_ctype) },
+ { &size_t_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted
+ { &intmax_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted
+ { &ptrdiff_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted
{ &const_ptr_ctype, T_PTR(&const_void_ctype) },
{ &const_string_ctype, T_PTR(&const_char_ctype) },
+ { &const_wstring_ctype,T_PTR(&const_wchar_ctype) },
{ &const_void_ctype, T_CONST(&void_ctype, NULL, NULL) },
{ &const_char_ctype, T_CONST(&char_ctype, &bits_in_char, &max_int_alignment)},
+ { &const_wchar_ctype, T_CONST(&int_ctype, NULL, NULL) },
+ { &volatile_void_ctype,T_NODE(MOD_VOLATILE, &void_ctype, NULL, NULL) },
+ { &volatile_ptr_ctype, T_PTR(&volatile_void_ctype) },
+ { &volatile_bool_ctype,T_NODE(MOD_VOLATILE, &bool_ctype, NULL, NULL) },
+ { &volatile_bool_ptr_ctype, T_PTR(&volatile_bool_ctype) },
{ NULL, }
};
@@ -931,4 +959,13 @@ void init_ctype(void)
intptr_ctype = ssize_t_ctype;
if (!uintptr_ctype)
uintptr_ctype = size_t_ctype;
+
+ size_t_ptr_ctype.ctype.base_type = size_t_ctype;
+ intmax_ptr_ctype.ctype.base_type = intmax_ctype;
+ ptrdiff_ptr_ctype.ctype.base_type = ptrdiff_ctype;
+
+ const_wchar_ctype.ctype.base_type = wchar_ctype;
+ const_wchar_ctype.rank = wchar_ctype->rank;
+ const_wchar_ctype.ctype.alignment = wchar_ctype->ctype.alignment;
+ const_wchar_ctype.bit_size = wchar_ctype->bit_size;
}
diff --git a/symbol.h b/symbol.h
index a3ed9567..5c5a7f12 100644
--- a/symbol.h
+++ b/symbol.h
@@ -185,6 +185,7 @@ struct symbol {
examined:1,
expanding:1,
evaluated:1,
+ has_flex_array:1,
string:1,
designated_init:1,
forced_arg:1,
@@ -298,14 +299,19 @@ extern struct symbol bool_ctype, void_ctype, type_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_ctype;
extern struct symbol autotype_ctype;
+extern struct symbol schar_ptr_ctype, short_ptr_ctype;
extern struct symbol int_ptr_ctype, uint_ptr_ctype;
extern struct symbol long_ptr_ctype, ulong_ptr_ctype;
extern struct symbol llong_ptr_ctype, ullong_ptr_ctype;
+extern struct symbol size_t_ptr_ctype, intmax_ptr_ctype, ptrdiff_ptr_ctype;
extern struct symbol float32_ctype, float32x_ctype;
extern struct symbol float64_ctype, float64x_ctype;
extern struct symbol float128_ctype;
extern struct symbol const_void_ctype, const_char_ctype;
extern struct symbol const_ptr_ctype, const_string_ctype;
+extern struct symbol const_wchar_ctype, const_wstring_ctype;
+extern struct symbol volatile_void_ctype, volatile_ptr_ctype;
+extern struct symbol volatile_bool_ctype, volatile_bool_ptr_ctype;
/* Special internal symbols */
extern struct symbol zero_int;
@@ -421,6 +427,20 @@ static inline int is_array_type(struct symbol *type)
return type->type == SYM_ARRAY;
}
+static inline int is_struct_type(struct symbol *type)
+{
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ return type->type == SYM_STRUCT;
+}
+
+static inline int is_union_type(struct symbol *type)
+{
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ return type->type == SYM_UNION;
+}
+
static inline int is_float_type(struct symbol *type)
{
if (type->type == SYM_NODE)
@@ -506,6 +526,13 @@ static inline int is_extern_inline(struct symbol *sym)
is_function(sym->ctype.base_type);
}
+static inline int has_flexible_array(struct symbol *type)
+{
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ return type->has_flex_array;
+}
+
static inline int get_sym_type(struct symbol *type)
{
if (type->type == SYM_NODE)
diff --git a/target-x86.c b/target-x86.c
index b7ff8f2a..9d82869a 100644
--- a/target-x86.c
+++ b/target-x86.c
@@ -1,6 +1,7 @@
#include "symbol.h"
#include "target.h"
#include "machine.h"
+#include "builtin.h"
static void predefine_i386(const struct target *self)
@@ -39,6 +40,11 @@ static void init_x86_common(const struct target *target)
}
}
+static const struct builtin_fn builtins_x86_common[] = {
+ { "__builtin_ia32_pause", &void_ctype, 0, },
+ { }
+};
+
static void init_i386(const struct target *target)
{
@@ -64,6 +70,7 @@ const struct target target_i386 = {
.init = init_i386,
.predefine = predefine_i386,
+ .builtins = builtins_x86_common,
};
@@ -159,4 +166,5 @@ const struct target target_x86_64 = {
.init = init_x86_64,
.predefine = predefine_x86_64,
+ .builtins = builtins_x86_common,
};
diff --git a/validation/builtin-arith.c b/validation/builtin-arith.c
index d08c93da..3ce59304 100644
--- a/validation/builtin-arith.c
+++ b/validation/builtin-arith.c
@@ -31,22 +31,27 @@ void test(void (*fun)(void))
/*
* check-name: builtin arithmetic
* check-command: sparse -Wno-decl $file
- * check-known-to-fail
*
* check-error-start
-builtin-arith.c:10:xx: error: ...
-builtin-arith.c:11:xx: error: ...
-builtin-arith.c:13:xx: error: arithmetics on pointers to functions
-builtin-arith.c:14:xx: error: arithmetics on pointers to functions
-builtin-arith.c:15:xx: error: arithmetics on pointers to functions
-builtin-arith.c:18:xx: error: ...
-builtin-arith.c:19:xx: error: ...
-builtin-arith.c:21:xx: error: ...
-builtin-arith.c:22:xx: error: ...
-builtin-arith.c:23:xx: error: ...
-builtin-arith.c:24:xx: error: ...
-builtin-arith.c:25:xx: error: ...
+builtin-arith.c:10:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:11:13: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:12:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:13:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:13:29: error: arithmetics on pointers to functions
+builtin-arith.c:14:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:14:29: error: arithmetics on pointers to functions
+builtin-arith.c:15:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:15:29: error: arithmetics on pointers to functions
+builtin-arith.c:18:21: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:19:29: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:21:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:22:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:23:14: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:24:21: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:25:21: error: taking the address of built-in function '__builtin_trap'
+builtin-arith.c:27:9: error: taking the address of built-in function '__builtin_trap'
builtin-arith.c:27:24: error: subtraction of functions? Share your drugs
+builtin-arith.c:28:15: error: taking the address of built-in function '__builtin_trap'
builtin-arith.c:28:13: error: subtraction of functions? Share your drugs
* check-error-end
*/
diff --git a/validation/builtin-atomic-clear.c b/validation/builtin-atomic-clear.c
new file mode 100644
index 00000000..ef430c64
--- /dev/null
+++ b/validation/builtin-atomic-clear.c
@@ -0,0 +1,15 @@
+void foo(void *ptr, _Bool *bptr, volatile void *vptr, volatile _Bool *vbptr, int mo)
+{
+ __atomic_clear(ptr, mo);
+ __atomic_clear(bptr, mo);
+ __atomic_clear(vptr, mo);
+ __atomic_clear(vbptr, mo);
+}
+
+/*
+ * check-name: builtin-atomic-clear
+ *
+ * check-error-start
+builtin-atomic-clear.c:1:6: warning: symbol 'foo' was not declared. Should it be static?
+ * check-error-end
+ */
diff --git a/validation/builtin-sync-fetch.c b/validation/builtin-sync-fetch.c
new file mode 100644
index 00000000..45139a3c
--- /dev/null
+++ b/validation/builtin-sync-fetch.c
@@ -0,0 +1,24 @@
+static int ok_int(int *ptr, int val)
+{
+ return __sync_add_and_fetch(ptr, val);
+}
+
+static long* ok_ptr(long **ptr, long *val)
+{
+ return __sync_add_and_fetch(ptr, val);
+}
+
+static void chk_ret_ok(long *ptr, long val)
+{
+ _Static_assert([typeof(__sync_add_and_fetch(ptr, val))] == [long], "");
+}
+
+static int chk_val(int *ptr, long val)
+{
+ // OK: val is converted to an int
+ return __sync_add_and_fetch(ptr, val);
+}
+
+/*
+ * check-name: builtin-sync-fetch
+ */
diff --git a/validation/crash-undef-in-parens.c b/validation/crash-undef-in-parens.c
new file mode 100644
index 00000000..5f05f88a
--- /dev/null
+++ b/validation/crash-undef-in-parens.c
@@ -0,0 +1,9 @@
+void foo(void) { return (UNDEF_STUFF_IN_PARENS); }
+
+/*
+ * check-name: crash-undef-in-parens
+ *
+ * check-error-start
+crash-undef-in-parens.c:1:26: error: undefined identifier 'UNDEF_STUFF_IN_PARENS'
+ * check-error-end
+ */
diff --git a/validation/flex-array-align.c b/validation/flex-array-align.c
new file mode 100644
index 00000000..9f28942a
--- /dev/null
+++ b/validation/flex-array-align.c
@@ -0,0 +1,18 @@
+struct s {
+ __INT32_TYPE__ x;
+ __INT16_TYPE__ y;
+ unsigned char f[];
+};
+
+static int foo(struct s *s)
+{
+ return (sizeof(*s) << 16) | __builtin_offsetof(typeof(*s), f);
+}
+
+/*
+ * check-name: flex-array-align
+ * check-command: test-linearize -Wno-flexible-array-sizeof $file
+ *
+ * check-output-ignore
+ * check-output-contains: ret\\..*\\$0x80006
+ */
diff --git a/validation/flex-array-array.c b/validation/flex-array-array.c
new file mode 100644
index 00000000..921a0698
--- /dev/null
+++ b/validation/flex-array-array.c
@@ -0,0 +1,15 @@
+struct s {
+ int i;
+ long f[];
+};
+
+static struct s a[2];
+
+/*
+ * check-name: flex-array-array
+ * check-command: sparse -Wflexible-array-array $file
+ *
+ * check-error-start
+flex-array-array.c:6:18: warning: array of flexible structures
+ * check-error-end
+ */
diff --git a/validation/flex-array-error.c b/validation/flex-array-error.c
new file mode 100644
index 00000000..2b7e6953
--- /dev/null
+++ b/validation/flex-array-error.c
@@ -0,0 +1,26 @@
+struct s {
+ int i;
+ long f[];
+ int j;
+};
+
+union u {
+ int i;
+ long f[];
+};
+
+// trigger the examination of the offending types
+static int foo(struct s *s, union u *u)
+{
+ return __builtin_offsetof(typeof(*s), i)
+ + __builtin_offsetof(typeof(*u), i);
+}
+
+/*
+ * check-name: flex-array-error
+ *
+ * check-error-start
+flex-array-error.c:3:14: error: flexible array member 'f' is not last
+flex-array-error.c:9:14: error: flexible array member 'f' in a union
+ * check-error-end
+ */
diff --git a/validation/flex-array-nested.c b/validation/flex-array-nested.c
new file mode 100644
index 00000000..094de2fb
--- /dev/null
+++ b/validation/flex-array-nested.c
@@ -0,0 +1,29 @@
+struct f {
+ int i;
+ long f[];
+};
+
+struct s {
+ struct f f;
+};
+
+union u {
+ struct f f;
+};
+
+// trigger the examination of the offending types
+static int foo(struct s *s, union u *u)
+{
+ return __builtin_offsetof(typeof(*s), f)
+ + __builtin_offsetof(typeof(*u), f);
+}
+
+/*
+ * check-name: flex-array-nested
+ * check-command: sparse -Wflexible-array-nested $file
+ *
+ * check-error-start
+flex-array-nested.c:7:18: warning: nested flexible array
+flex-array-nested.c:11:18: warning: nested flexible array
+ * check-error-end
+ */
diff --git a/validation/flex-array-sizeof.c b/validation/flex-array-sizeof.c
new file mode 100644
index 00000000..05394e19
--- /dev/null
+++ b/validation/flex-array-sizeof.c
@@ -0,0 +1,18 @@
+struct s {
+ int i;
+ long f[];
+};
+
+static int foo(struct s *s)
+{
+ return sizeof(*s);
+}
+
+/*
+ * check-name: flex-array-sizeof
+ * check-command: sparse -Wflexible-array-sizeof $file
+ *
+ * check-error-start
+flex-array-sizeof.c:8:16: warning: using sizeof on a flexible structure
+ * check-error-end
+ */
diff --git a/validation/flex-array-union-array-no.c b/validation/flex-array-union-array-no.c
new file mode 100644
index 00000000..5a1de787
--- /dev/null
+++ b/validation/flex-array-union-array-no.c
@@ -0,0 +1,9 @@
+#include "flex-array-union-array.h"
+
+/*
+ * check-name: flex-array-union-no
+ * check-command: sparse -Wflexible-array-array -Wno-flexible-array-union $file
+ *
+ * check-error-start
+ * check-error-end
+ */
diff --git a/validation/flex-array-union-array-yes.c b/validation/flex-array-union-array-yes.c
new file mode 100644
index 00000000..c2b71d65
--- /dev/null
+++ b/validation/flex-array-union-array-yes.c
@@ -0,0 +1,11 @@
+#include "flex-array-union-array.h"
+
+/*
+ * check-name: flex-array-union-yes
+ * check-command: sparse -Wflexible-array-array -Wflexible-array-union $file
+ *
+ * check-error-start
+flex-array-union-array-yes.c: note: in included file:
+flex-array-union-array.h:11:17: warning: array of flexible structures
+ * check-error-end
+ */
diff --git a/validation/flex-array-union-array.h b/validation/flex-array-union-array.h
new file mode 100644
index 00000000..b2a74d1a
--- /dev/null
+++ b/validation/flex-array-union-array.h
@@ -0,0 +1,11 @@
+struct s_flex {
+ int i;
+ long f[];
+};
+
+union s {
+ struct s_flex flex;
+ char buf[200];
+};
+
+static union s a[2];
diff --git a/validation/linear/bool-cast-lp32.c b/validation/linear/bool-cast-lp32.c
index 44a650f4..7aab31dd 100644
--- a/validation/linear/bool-cast-lp32.c
+++ b/validation/linear/bool-cast-lp32.c
@@ -12,7 +12,6 @@ static _Bool ffun_e(void) { return (_Bool)ffun; }
/*
* check-name: bool-cast-pointer
* check-command: test-linearize -m32 -fdump-ir $file
- * check-known-to-fail
*
* check-output-ignore
* check-output-excludes: ptrtu\\.
diff --git a/validation/optim/canonical-mul.c b/validation/optim/canonical-mul.c
index 3ae9e3a6..0c14226f 100644
--- a/validation/optim/canonical-mul.c
+++ b/validation/optim/canonical-mul.c
@@ -7,7 +7,7 @@ uint xtc_umul_ytc(uint x, uint y) { return (x * 3) * (y * 2); }
* check-description:
* 1) verify that constants in mul chains are
* pushed at the right of the whole chain.
- * For example '(a * 3) * b' must be canonicalized into '(a * b) * 1'
+ * For example '(a * 3) * b' must be canonicalized into '(a * b) * 3'
* This is needed in general for constant simplification;
* for example, for:
* '(a * 3) * (b * 2)'
diff --git a/validation/usual-conv-lp32.c b/validation/usual-conv-lp32.c
new file mode 100644
index 00000000..7f91288e
--- /dev/null
+++ b/validation/usual-conv-lp32.c
@@ -0,0 +1,11 @@
+extern long l;
+extern unsigned int u;
+
+#if __SIZEOF_LONG__ == __SIZEOF_INT__
+_Static_assert([typeof(l + u)] == [unsigned long], "ulong");
+#endif
+
+/*
+ * check-name: usual-conversions
+ * check-command: sparse -m32 $file
+ */