aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--Documentation/test-suite8
-rw-r--r--Makefile10
-rwxr-xr-xcgcc11
-rw-r--r--evaluate.c2
-rw-r--r--graph.c8
-rw-r--r--lib.c25
-rw-r--r--lib.h1
-rw-r--r--linearize.h4
-rw-r--r--liveness.c2
-rw-r--r--parse.c14
-rw-r--r--pre-process.c4
-rw-r--r--simplify.c3
-rw-r--r--sparse.c33
-rw-r--r--symbol.c14
-rw-r--r--symbol.h4
-rw-r--r--validation/compound-sizes.c88
-rw-r--r--validation/linear/range-op.c31
-rw-r--r--validation/preprocessor/phase2-backslash.c (renamed from validation/phase2/backslash)29
-rw-r--r--validation/preprocessor/phase3-comments.c (renamed from validation/phase3/comments)12
-rw-r--r--validation/range-syntax.c23
-rwxr-xr-xvalidation/test-suite26
-rw-r--r--validation/typedef-redef-c89.c13
-rw-r--r--validation/typedef-redef.c13
-rw-r--r--validation/typediff-arraysize.c12
-rw-r--r--validation/typediff-enum.c34
25 files changed, 385 insertions, 39 deletions
diff --git a/Documentation/test-suite b/Documentation/test-suite
index 1315dbd6..bf4518a2 100644
--- a/Documentation/test-suite
+++ b/Documentation/test-suite
@@ -27,6 +27,14 @@ check-arch-only: <arch[|...]>
Ignore the test if the current architecture (as returned by 'uname -m')
match or not one of the archs given in the pattern.
+check-assert: <condition>
+ Ignore the test if the given condition is false when evaluated as a
+ static assertion (_Static_assert).
+
+check-cpp-if: <condition>
+ Ignore the test if the given condition is false when evaluated
+ by sparse's pre-processor.
+
check-exit-value: <value>
The expected exit value of check-command. It defaults to 0.
diff --git a/Makefile b/Makefile
index 5548f848..ced70dc7 100644
--- a/Makefile
+++ b/Makefile
@@ -143,7 +143,11 @@ endif
LLVM_CONFIG:=llvm-config
HAVE_LLVM:=$(shell $(LLVM_CONFIG) --version >/dev/null 2>&1 && echo 'yes')
ifeq ($(HAVE_LLVM),yes)
-ifeq ($(shell uname -m | grep -q '\(i[3456]86\|x86\|amd64\)' && echo ok),ok)
+arch := $(shell uname -m)
+ifeq (${MULTIARCH_TRIPLET},x86_64-linux-gnux32)
+arch := x32
+endif
+ifneq ($(filter ${arch},i386 i486 i586 i686 x86_64 amd64),)
LLVM_VERSION:=$(shell $(LLVM_CONFIG) --version)
ifeq ($(shell expr "$(LLVM_VERSION)" : '[3-9]\.'),2)
LLVM_PROGS := sparse-llvm
@@ -161,7 +165,7 @@ else
$(warning LLVM 3.0 or later required. Your system has version $(LLVM_VERSION) installed.)
endif
else
-$(warning sparse-llvm disabled on $(shell uname -m))
+$(warning sparse-llvm disabled on ${arch})
endif
else
$(warning Your system does not have llvm, disabling sparse-llvm)
@@ -201,7 +205,7 @@ cflags += $($(*)-cflags) $(CPPFLAGS) $(CFLAGS)
selfcheck: $(OBJS:.o=.sc)
-SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)')
+SPARSE_VERSION:=$(shell git describe --dirty 2>/dev/null || echo '$(VERSION)')
lib.o: version.h
version.h: FORCE
@echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h.tmp
diff --git a/cgcc b/cgcc
index 1f7b625c..a28b140e 100755
--- a/cgcc
+++ b/cgcc
@@ -265,10 +265,7 @@ sub add_specs {
" -D'__declspec(x)=__attribute__((x))'";
} elsif ($spec eq 'i86') {
return (' -D__i386=1 -D__i386__=1' .
- &integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
- &float_types (1, 1, 21, [24,8], [53,11], [64,15]) .
- &define_size_t ($m64 ? "long unsigned int" : "unsigned int") .
- ' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
+ &float_types (1, 1, 21, [24,8], [53,11], [64,15]));
} elsif ($spec eq 'sparc') {
return (' -D__sparc=1 -D__sparc__=1' .
&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
@@ -282,11 +279,7 @@ sub add_specs {
&define_size_t ("long unsigned int") .
' -D__SIZEOF_POINTER__=8');
} elsif ($spec eq 'x86_64') {
- return (' -D__x86_64=1 -D__x86_64__=1' . ($m32 ? '' : ' -D__LP64__=1') .
- &integer_types (8, 16, 32, $m32 ? 32 : 64, 64, 128) .
- &float_types (1, 1, 33, [24,8], [53,11], [113,15]) .
- &define_size_t ($m32 ? "unsigned int" : "long unsigned int") .
- ' -D__SIZEOF_POINTER__=' . ($m32 ? '4' : '8'));
+ return &float_types (1, 1, 33, [24,8], [53,11], [113,15]);
} elsif ($spec eq 'ppc') {
return (' -D__powerpc__=1 -D_BIG_ENDIAN -D_STRING_ARCH_unaligned=1' .
&integer_types (8, 16, 32, $m64 ? 64 : 32, 64) .
diff --git a/evaluate.c b/evaluate.c
index 0d50220a..ab4d1ba6 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3291,7 +3291,7 @@ struct symbol *evaluate_expression(struct expression *expr)
return NULL;
}
-static void check_duplicates(struct symbol *sym)
+void check_duplicates(struct symbol *sym)
{
int declared = 0;
struct symbol *next = sym;
diff --git a/graph.c b/graph.c
index a24c6e17..d598a18a 100644
--- a/graph.c
+++ b/graph.c
@@ -78,15 +78,15 @@ static void graph_ep(struct entrypoint *ep)
continue;
switch(insn->opcode) {
case OP_STORE:
- if (insn->symbol->type == PSEUDO_SYM) {
- printf("%s store(%s)", s, show_ident(insn->symbol->sym->ident));
+ if (insn->src->type == PSEUDO_SYM) {
+ printf("%s store(%s)", s, show_ident(insn->src->sym->ident));
s = ",";
}
break;
case OP_LOAD:
- if (insn->symbol->type == PSEUDO_SYM) {
- printf("%s load(%s)", s, show_ident(insn->symbol->sym->ident));
+ if (insn->src->type == PSEUDO_SYM) {
+ printf("%s load(%s)", s, show_ident(insn->src->sym->ident));
s = ",";
}
break;
diff --git a/lib.c b/lib.c
index b94ed847..b5eb47d0 100644
--- a/lib.c
+++ b/lib.c
@@ -259,6 +259,7 @@ int dump_macro_defs = 0;
int dbg_entry = 0;
int dbg_dead = 0;
+int dbg_compound = 0;
unsigned long fdump_ir;
int fmem_report = 0;
@@ -276,12 +277,17 @@ static enum { STANDARD_C89,
STANDARD_GNU89,
STANDARD_GNU99, } standard = STANDARD_GNU89;
-#define ARCH_LP32 0
-#define ARCH_LP64 1
-#define ARCH_LLP64 2
+enum {
+ ARCH_LP32,
+ ARCH_X32,
+ ARCH_LP64,
+ ARCH_LLP64,
+};
#ifdef __LP64__
#define ARCH_M64_DEFAULT ARCH_LP64
+#elif defined(__x86_64__) || defined(__x86_64)
+#define ARCH_M64_DEFAULT ARCH_X32
#else
#define ARCH_M64_DEFAULT ARCH_LP32
#endif
@@ -425,6 +431,8 @@ static char **handle_switch_m(char *arg, char **next)
arch_m64 = ARCH_LP64;
} else if (!strcmp(arg, "m32")) {
arch_m64 = ARCH_LP32;
+ } else if (!strcmp(arg, "mx32")) {
+ arch_m64 = ARCH_X32;
} else if (!strcmp(arg, "msize-llp64")) {
arch_m64 = ARCH_LLP64;
} else if (!strcmp(arg, "msize-long")) {
@@ -442,6 +450,11 @@ static char **handle_switch_m(char *arg, char **next)
static void handle_arch_m64_finalize(void)
{
switch (arch_m64) {
+ case ARCH_X32:
+ max_int_alignment = 8;
+ add_pre_buffer("#weak_define __ILP32__ 1\n");
+ add_pre_buffer("#weak_define _ILP32 1\n");
+ goto case_x86_64;
case ARCH_LP32:
/* default values */
return;
@@ -463,8 +476,11 @@ static void handle_arch_m64_finalize(void)
case_64bit_common:
bits_in_pointer = 64;
pointer_alignment = 8;
-#ifdef __x86_64__
+ /* fall through */
+ case_x86_64:
+#if defined(__x86_64__) || defined(__x86_64)
add_pre_buffer("#weak_define __x86_64__ 1\n");
+ add_pre_buffer("#weak_define __x86_64 1\n");
#endif
break;
}
@@ -719,6 +735,7 @@ static char **handle_switch_W(char *arg, char **next)
static struct flag debugs[] = {
{ "entry", &dbg_entry},
{ "dead", &dbg_dead},
+ { "compound", &dbg_compound},
};
diff --git a/lib.h b/lib.h
index e34bb9a0..aea46741 100644
--- a/lib.h
+++ b/lib.h
@@ -168,6 +168,7 @@ extern int dump_macro_defs;
extern int dbg_entry;
extern int dbg_dead;
+extern int dbg_compound;
extern unsigned int fmax_warnings;
extern int fmem_report;
diff --git a/linearize.h b/linearize.h
index 8790b7e5..db4a67f3 100644
--- a/linearize.h
+++ b/linearize.h
@@ -117,8 +117,10 @@ struct instruction {
pseudo_t base;
unsigned from, len;
};
- struct /* setval and symaddr */ {
+ struct /* symaddr */ {
pseudo_t symbol; /* Subtle: same offset as "src" !! */
+ };
+ struct /* setval */ {
struct expression *val;
};
struct /* setfval */ {
diff --git a/liveness.c b/liveness.c
index d85cea39..e0e58329 100644
--- a/liveness.c
+++ b/liveness.c
@@ -71,7 +71,7 @@ static void track_instruction_usage(struct basic_block *bb, struct instruction *
break;
/* Uni */
- case OP_NOT: case OP_NEG:
+ case OP_NOT: case OP_NEG: case OP_FNEG:
USES(src1); DEFINES(target);
break;
diff --git a/parse.c b/parse.c
index bb504d21..d94c53a2 100644
--- a/parse.c
+++ b/parse.c
@@ -458,6 +458,11 @@ static struct init_keyword {
{ "__builtin_ms_va_list", NS_TYPEDEF, .type = &ptr_ctype, .op = &spec_op },
{ "__int128_t", NS_TYPEDEF, .type = &lllong_ctype, .op = &spec_op },
{ "__uint128_t",NS_TYPEDEF, .type = &ulllong_ctype, .op = &spec_op },
+ { "_Float32", NS_TYPEDEF, .type = &float32_ctype, .op = &spec_op },
+ { "_Float32x", NS_TYPEDEF, .type = &float32x_ctype, .op = &spec_op },
+ { "_Float64", NS_TYPEDEF, .type = &float64_ctype, .op = &spec_op },
+ { "_Float64x", NS_TYPEDEF, .type = &float64x_ctype, .op = &spec_op },
+ { "_Float128", NS_TYPEDEF, .type = &float128_ctype, .op = &spec_op },
/* Extended types */
{ "typeof", NS_TYPEDEF, .op = &typeof_op },
@@ -2367,11 +2372,14 @@ static struct token *parse_context_statement(struct token *token, struct stateme
static struct token *parse_range_statement(struct token *token, struct statement *stmt)
{
stmt->type = STMT_RANGE;
- token = assignment_expression(token->next, &stmt->range_expression);
+ token = token->next;
+ token = expect(token, '(', "after __range__ statement");
+ token = assignment_expression(token, &stmt->range_expression);
token = expect(token, ',', "after range expression");
token = assignment_expression(token, &stmt->range_low);
token = expect(token, ',', "after low range");
token = assignment_expression(token, &stmt->range_high);
+ token = expect(token, ')', "after range statement");
return expect(token, ';', "after range statement");
}
@@ -2888,6 +2896,10 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
if (decl->same_symbol) {
decl->definition = decl->same_symbol->definition;
decl->op = decl->same_symbol->op;
+ if (is_typedef) {
+ // TODO: handle -std=c89 --pedantic
+ check_duplicates(decl);
+ }
}
if (!match_op(token, ','))
diff --git a/pre-process.c b/pre-process.c
index c6c6cdad..7d335ab0 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -848,6 +848,10 @@ static void set_stream_include_path(struct stream *stream)
includepath[0] = path;
}
+#ifndef PATH_MAX
+#define PATH_MAX 4096 // for Hurd where it's not defined
+#endif
+
static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
{
int fd;
diff --git a/simplify.c b/simplify.c
index 2c29bc30..be720860 100644
--- a/simplify.c
+++ b/simplify.c
@@ -350,6 +350,7 @@ static int replace_with_pseudo(struct instruction *insn, pseudo_t pseudo)
kill_use(&insn->src2);
case OP_NOT:
case OP_NEG:
+ case OP_FNEG:
case OP_SYMADDR:
case OP_CAST:
case OP_SCAST:
@@ -1208,7 +1209,7 @@ int simplify_instruction(struct instruction *insn)
case OP_LSR: case OP_ASR:
return simplify_binop(insn);
- case OP_NOT: case OP_NEG:
+ case OP_NOT: case OP_NEG: case OP_FNEG:
return simplify_unop(insn);
case OP_LOAD:
if (!has_users(insn->target))
diff --git a/sparse.c b/sparse.c
index 9d1cdc51..056d14ff 100644
--- a/sparse.c
+++ b/sparse.c
@@ -274,6 +274,37 @@ static void check_context(struct entrypoint *ep)
check_bb_context(ep, ep->entry->bb, in_context, out_context);
}
+/* list_compound_symbol - symbol info for arrays, structures, unions */
+static void list_compound_symbol(struct symbol *sym)
+{
+ struct symbol *base;
+
+ /* Only show symbols that have a positive size */
+ if (sym->bit_size <= 0)
+ return;
+ if (!sym->ctype.base_type)
+ return;
+ /* Don't show unnamed types */
+ if (!sym->ident)
+ return;
+
+ if (sym->type == SYM_NODE)
+ base = sym->ctype.base_type;
+ else
+ base = sym;
+ switch (base->type) {
+ case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY:
+ break;
+ default:
+ return;
+ }
+
+ info(sym->pos, "%s: compound size %u, alignment %lu",
+ show_typename(sym),
+ bits_to_bytes(sym->bit_size),
+ sym->ctype.alignment);
+}
+
static void check_symbols(struct symbol_list *list)
{
struct symbol *sym;
@@ -289,6 +320,8 @@ static void check_symbols(struct symbol_list *list)
check_context(ep);
}
+ if (dbg_compound)
+ list_compound_symbol(sym);
} END_FOR_EACH_PTR(sym);
if (Wsparse_error && die_if_error)
diff --git a/symbol.c b/symbol.c
index e14d2306..3205150f 100644
--- a/symbol.c
+++ b/symbol.c
@@ -696,6 +696,9 @@ struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_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;
@@ -719,6 +722,11 @@ void init_symbols(void)
init_builtins(stream);
}
+// For fix-sized types
+static int bits_in_type32 = 32;
+static int bits_in_type64 = 64;
+static int bits_in_type128 = 128;
+
#define MOD_ESIGNED (MOD_SIGNED | MOD_EXPLICITLY_SIGNED)
#define MOD_LL (MOD_LONG | MOD_LONGLONG)
#define MOD_LLL MOD_LONGLONGLONG
@@ -759,6 +767,12 @@ static const struct ctype_declare {
{ &double_ctype, SYM_BASETYPE, MOD_LONG, &bits_in_double, &max_fp_alignment, &fp_type },
{ &ldouble_ctype, SYM_BASETYPE, MOD_LONG | MOD_LONGLONG, &bits_in_longdouble, &max_fp_alignment, &fp_type },
+ { &float32_ctype, SYM_BASETYPE, 0, &bits_in_type32, &max_fp_alignment, &fp_type },
+ { &float32x_ctype, SYM_BASETYPE, MOD_LONG, &bits_in_double, &max_fp_alignment, &fp_type },
+ { &float64_ctype, SYM_BASETYPE, 0, &bits_in_type64, &max_fp_alignment, &fp_type },
+ { &float64x_ctype, SYM_BASETYPE, MOD_LONG | MOD_LONGLONG, &bits_in_longdouble, &max_fp_alignment, &fp_type },
+ { &float128_ctype, SYM_BASETYPE, 0, &bits_in_type128, &max_alignment, &fp_type },
+
{ &string_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &char_ctype },
{ &ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
{ &null_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype },
diff --git a/symbol.h b/symbol.h
index dc6de8fa..4edb4404 100644
--- a/symbol.h
+++ b/symbol.h
@@ -267,6 +267,9 @@ extern struct symbol bool_ctype, void_ctype, type_ctype,
string_ctype, ptr_ctype, lazy_ptr_ctype,
incomplete_ctype, label_ctype, bad_ctype,
null_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;
@@ -311,6 +314,7 @@ extern const char* get_type_name(enum type type);
extern void debug_symbol(struct symbol *);
extern void merge_type(struct symbol *sym, struct symbol *base_type);
extern void check_declaration(struct symbol *sym);
+extern void check_duplicates(struct symbol *sym);
static inline int valid_type(const struct symbol *ctype)
{
diff --git a/validation/compound-sizes.c b/validation/compound-sizes.c
new file mode 100644
index 00000000..d8ccf605
--- /dev/null
+++ b/validation/compound-sizes.c
@@ -0,0 +1,88 @@
+// This tests sparse "-vcompound" output.
+#define NULL ((void*)0)
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+// Do not list functions.
+static int do_nothing(void)
+{}
+
+// no:
+static inline int zero(void)
+{
+ return 0 / 1;
+}
+
+// no:
+struct inventory {
+ unsigned char description[64];
+ unsigned char department[64];
+ uint32_t dept_number;
+ uint32_t item_cost;
+ uint64_t stock_number;
+ uint32_t tally[12]; // per month
+};
+
+// no
+static struct inventory *get_inv(uint64_t stocknum)
+{
+ return NULL;
+}
+
+// no
+union un {
+ struct inventory inv;
+ unsigned char bytes[0];
+};
+
+// yes
+static union un un;
+
+// yes
+static struct inventory inven[100];
+
+// no
+typedef struct inventory inventory_t;
+
+// no
+static struct inventory *invptr;
+
+// yes
+static inventory_t invent[10];
+
+// no
+static float floater;
+static double double_float;
+
+// yes
+static float floats[42];
+static double doubles[84];
+
+// no
+int main(void)
+{
+ // no, these are not global.
+ struct inventory inv[10];
+ inventory_t invt[10];
+ // what about statics?
+ static struct inventory invtop;
+ static inventory_t inv_top;
+ static uint64_t stocknums[100];
+
+ invptr = get_inv(42000);
+ return 0;
+}
+
+/*
+ * check-name: compound-sizes
+ * check-command: sparse -vcompound $file
+ * check-assert: _Alignof(long long) == 8
+ *
+ * check-error-start
+compound-sizes.c:39:17: union un static [toplevel] un: compound size 192, alignment 8
+compound-sizes.c:42:25: struct inventory static [toplevel] inven[100]: compound size 19200, alignment 8
+compound-sizes.c:51:33: struct inventory static [toplevel] [usertype] invent[10]: compound size 1920, alignment 8
+compound-sizes.c:58:25: float static [toplevel] floats[42]: compound size 168, alignment 4
+compound-sizes.c:59:25: double static [toplevel] doubles[84]: compound size 672, alignment 8
+ * check-error-end
+ */
diff --git a/validation/linear/range-op.c b/validation/linear/range-op.c
new file mode 100644
index 00000000..4472bb33
--- /dev/null
+++ b/validation/linear/range-op.c
@@ -0,0 +1,31 @@
+static void foo(int a)
+{
+ __range__(a, 0, 8);
+}
+
+static void bar(int a, int b, int c)
+{
+ __range__(a, b, c);
+}
+
+/*
+ * check-name: range-op
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+foo:
+.L0:
+ <entry-point>
+ range-check %arg1 between $0..$8
+ ret
+
+
+bar:
+.L2:
+ <entry-point>
+ range-check %arg1 between %arg2..%arg3
+ ret
+
+
+ * check-output-end
+ */
diff --git a/validation/phase2/backslash b/validation/preprocessor/phase2-backslash.c
index 29c85b4d..21d94d7d 100644
--- a/validation/phase2/backslash
+++ b/validation/preprocessor/phase2-backslash.c
@@ -17,11 +17,26 @@
* the rest of tokenizer.
*/
+/*
+ * check-name: phase2-backslash
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"\a"
+1
+D
+'\a'
+ * check-output-end
+ *
+ * check-error-start
+preprocessor/phase2-backslash.c:68:0: warning: backslash-newline at end of file
+ * check-error-end
+ */
+
#define A(x) #x
#define B(x) A(x)
/* This should result in "\a" */
-/* XXX: currently sparse produces "a" */
-/* Partially fixed: now it gives "\\a", which is a separate problem */
B(\a)
#define C\
@@ -32,31 +47,21 @@ C
#define D\
1
/* And this should give D, since '\n' is removed and we get no whitespace */
-/* XXX: currently sparse produces 1 */
-/* Fixed */
D
#define E '\\
a'
/* This should give '\a' - with no warnings issued */
-/* XXX: currently sparse complains a lot and ends up producing a */
-/* Fixed */
E
/* This should give nothing */
-/* XXX: currently sparse produces more junk */
-/* Fixed */
// junk \
more junk
/* This should also give nothing */
-/* XXX: currently sparse produces / * comment * / */
-/* Fixed */
/\
* comment *\
/
/* And this should complain since final newline should not be eaten by '\\' */
-/* XXX: currently sparse does not notice */
-/* Fixed */
\
diff --git a/validation/phase3/comments b/validation/preprocessor/phase3-comments.c
index 8f51a307..7106b480 100644
--- a/validation/phase3/comments
+++ b/validation/preprocessor/phase3-comments.c
@@ -3,7 +3,15 @@
*/
/* This should give nothing */
-/* XXX: currently sparse produces Y */
-/* Fixed */
#define X /*
*/ Y
+
+/*
+ * check-name: phase3-comments
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+
+ * check-output-end
+ */
diff --git a/validation/range-syntax.c b/validation/range-syntax.c
new file mode 100644
index 00000000..c43fff0e
--- /dev/null
+++ b/validation/range-syntax.c
@@ -0,0 +1,23 @@
+
+static void ok(int a, int b, int c)
+{
+ __range__(a, 0, 8);
+ __range__(a, b, c);
+}
+
+static void ko(int a, int b, int c)
+{
+ __range__ a, 0, 8;
+ __range__ a, b, c;
+}
+
+/*
+ * check-name: range syntax
+ *
+ * check-error-start
+range-syntax.c:10:19: error: Expected ( after __range__ statement
+range-syntax.c:10:19: error: got a
+range-syntax.c:11:19: error: Expected ( after __range__ statement
+range-syntax.c:11:19: error: got a
+ * check-error-end
+ */
diff --git a/validation/test-suite b/validation/test-suite
index 4fdc9e9f..04607a3e 100755
--- a/validation/test-suite
+++ b/validation/test-suite
@@ -79,6 +79,8 @@ get_tag_value()
check_output_pattern=0
check_arch_ignore=""
check_arch_only=""
+ check_assert=""
+ check_cpp_if=""
lines=$(grep 'check-[a-z-]*' $1 | \
sed -e 's/^.*\(check-[a-z-]*:*\) *\(.*\)$/\1 \2/')
@@ -102,6 +104,8 @@ get_tag_value()
check_arch_ignore="$val" ;;
check-arch-only:) arch=$(uname -m)
check_arch_only="$val" ;;
+ check-assert:) check_assert="$val" ;;
+ check-cpp-if:) check_cpp_if="$val" ;;
check-description:) ;; # ignore
check-note:) ;; # ignore
@@ -301,6 +305,28 @@ do_test()
return 3
fi
fi
+ if [ "$check_assert" != "" ]; then
+ res=$(../sparse - 2>&1 >/dev/null <<- EOF
+ _Static_assert($check_assert, "$check_assert");
+ EOF
+ )
+ if [ "$res" != "" ]; then
+ disable "$test_name" "$file"
+ return 3
+ fi
+ fi
+ if [ "$check_cpp_if" != "" ]; then
+ res=$(../sparse -E - 2>/dev/null <<- EOF
+ #if !($check_cpp_if)
+ fail
+ #endif
+ EOF
+ )
+ if [ "$res" != "" ]; then
+ disable "$test_name" "$file"
+ return 3
+ fi
+ fi
if [ -z "$vquiet" ]; then
echo " TEST $test_name ($file)"
diff --git a/validation/typedef-redef-c89.c b/validation/typedef-redef-c89.c
new file mode 100644
index 00000000..6d4dc28c
--- /dev/null
+++ b/validation/typedef-redef-c89.c
@@ -0,0 +1,13 @@
+typedef int int_t;
+typedef int int_t;
+
+/*
+ * check-name: typedef-redef-c89
+ * check-command: sparse -std=c89 --pedantic $file
+ * check-known-to-fail
+ *
+ * check-error-start
+typedef-redef-c89.c:2:13: warning: redefinition of typedef 'int_t'
+typedef-redef-c89.c:1:13: info: originally defined here
+ * check-error-end
+ */
diff --git a/validation/typedef-redef.c b/validation/typedef-redef.c
new file mode 100644
index 00000000..3a60a773
--- /dev/null
+++ b/validation/typedef-redef.c
@@ -0,0 +1,13 @@
+typedef int ok_t;
+typedef int ok_t;
+
+typedef int ko_t;
+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
+ * check-error-end
+ */
diff --git a/validation/typediff-arraysize.c b/validation/typediff-arraysize.c
new file mode 100644
index 00000000..dd7a2ca5
--- /dev/null
+++ b/validation/typediff-arraysize.c
@@ -0,0 +1,12 @@
+extern int ok0[]; int ok0[1]; // OK
+extern int ok1[1]; int ok1[]; // OK but size should be 1
+extern int ko1[1]; int ko1[2]; // KO
+
+/*
+ * check-name: typediff-arraysize
+ * check-known-to-fail
+ *
+ * check-error-start
+typediff-arraysize.c:3:29: error: symbol 'ko1' redeclared with different type (originally declared at typediff-arraysize.c:3) - different array sizes
+ * check-error-end
+ */
diff --git a/validation/typediff-enum.c b/validation/typediff-enum.c
new file mode 100644
index 00000000..c5f2dc0a
--- /dev/null
+++ b/validation/typediff-enum.c
@@ -0,0 +1,34 @@
+enum num { ZERO, ONE, MANY, };
+typedef enum num num;
+
+extern int v;
+num v = 0;
+
+extern num w;
+int w = 0;
+
+int foo(void);
+num foo(void) { return ZERO; }
+
+num bar(void);
+int bar(void) { return ZERO; }
+
+void baz(int a);
+void baz(num a) { }
+
+void qux(num a);
+void qux(int a) { }
+
+/*
+ * check-name: typediff-enum
+ * check-known-to-fail
+ *
+ * check-error-start
+typediff-enum.c:5:5: error: symbol 'v' redeclared with different type (originally declared at typediff-enum.c:4) - different types
+typediff-enum.c:8:5: error: symbol 'w' redeclared with different type (originally declared at typediff-enum.c:7) - different types
+typediff-enum.c:11:5: error: symbol 'foo' redeclared with different type (originally declared at typediff-enum.c:10) - different types
+typediff-enum.c:14:5: error: symbol 'bar' redeclared with different type (originally declared at typediff-enum.c:13) - different types
+typediff-enum.c:17:6: error: symbol 'baz' redeclared with different type (originally declared at typediff-enum.c:16) - incompatible argument 1 (different types)
+typediff-enum.c:20:6: error: symbol 'qux' redeclared with different type (originally declared at typediff-enum.c:19) - incompatible argument 1 (different types)
+ * check-error-end
+ */