aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Documentation/index.rst6
-rw-r--r--Makefile14
-rw-r--r--builtin.c60
-rw-r--r--dissect.c19
-rw-r--r--evaluate.c45
-rw-r--r--evaluate.h7
-rw-r--r--expand.c18
-rw-r--r--expression.h1
-rw-r--r--inline.c8
-rw-r--r--lib.c4
-rw-r--r--lib.h4
-rw-r--r--linearize.c44
-rw-r--r--options.c6
-rw-r--r--parse.c75
-rw-r--r--pre-process.c8
-rw-r--r--semind.1 (renamed from sindex.1)24
-rw-r--r--semind.c (renamed from sindex.c)373
-rw-r--r--simplify.c20
-rw-r--r--sparse.12
-rw-r--r--symbol.c27
-rw-r--r--symbol.h14
-rw-r--r--target-xtensa.c5
-rw-r--r--token.h7
-rw-r--r--tokenize.c16
-rw-r--r--validation/abstract-array-declarator-quals.c21
-rw-r--r--validation/abstract-array-declarator-star.c8
-rw-r--r--validation/abstract-array-declarator.c11
-rw-r--r--validation/builtin-sync-cas.c25
-rw-r--r--validation/expand/bad-shift.c8
-rw-r--r--validation/init-wstring.c40
-rw-r--r--validation/init_cstring.c2
-rw-r--r--validation/inline-generic.c10
-rw-r--r--validation/linear/bug-assign-op0.c1
-rw-r--r--validation/linear/shift-assign1.c319
-rw-r--r--validation/linear/shift-assign2.c53
-rw-r--r--validation/optim/shift-big.c12
-rw-r--r--validation/preprocessor/bad-cmdline-include.c11
-rw-r--r--validation/shift-negative.c4
-rw-r--r--validation/shift-undef-long.c7
-rw-r--r--validation/shift-undef.c52
41 files changed, 1000 insertions, 393 deletions
diff --git a/.gitignore b/.gitignore
index 58598364..63c74afd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,7 @@ graph
obfuscate
sparse
sparse-llvm
-sindex
+semind
test-dissect
test-inspect
test-lexing
diff --git a/Documentation/index.rst b/Documentation/index.rst
index 737f4423..50afa558 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -26,7 +26,7 @@ Getting Sparse
--------------
You can find tarballs of released versions of Sparse at
-http://www.kernel.org/pub/software/devel/sparse/dist/.
+https://www.kernel.org/pub/software/devel/sparse/dist/.
The most recent version can be obtained directly from the Git
repository with the command::
@@ -60,8 +60,8 @@ archives at https://marc.info/?l=linux-sparse.
To subscribe to the list, send an email with
``subscribe linux-sparse`` in the body to ``majordomo@vger.kernel.org``.
-Bugs can also be reported and tracked via the Linux kernel's bugzilla:
-http://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools.
+Bugs can also be reported and tracked via the `Linux kernel's bugzilla for sparse
+<https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools>`_.
User documentation
------------------
diff --git a/Makefile b/Makefile
index fea2d74f..639d4f51 100644
--- a/Makefile
+++ b/Makefile
@@ -157,17 +157,17 @@ ifeq ($(HAVE_SQLITE),yes)
SQLITE_VERSION:=$(shell $(PKG_CONFIG) --modversion sqlite3)
SQLITE_VNUMBER:=$(shell printf '%d%02d%02d' $(subst ., ,$(SQLITE_VERSION)))
ifeq ($(shell expr "$(SQLITE_VNUMBER)" '>=' 32400),1)
-PROGRAMS += sindex
-INST_PROGRAMS += sindex
-INST_MAN1 += sindex.1
-sindex-ldlibs := $(shell $(PKG_CONFIG) --libs sqlite3)
-sindex-cflags := $(shell $(PKG_CONFIG) --cflags sqlite3)
-sindex-cflags += -std=gnu99
+PROGRAMS += semind
+INST_PROGRAMS += semind
+INST_MAN1 += semind.1
+semind-ldlibs := $(shell $(PKG_CONFIG) --libs sqlite3)
+semind-cflags := $(shell $(PKG_CONFIG) --cflags sqlite3)
+semind-cflags += -std=gnu99
else
$(warning Your SQLite3 version ($(SQLITE_VERSION)) is too old, 3.24.0 or later is required.)
endif
else
-$(warning Your system does not have sqlite3, disabling sindex)
+$(warning Your system does not have sqlite3, disabling semind)
endif
# Can we use gtk (needed for test-inspect)
diff --git a/builtin.c b/builtin.c
index f29b4a8d..2e9be8be 100644
--- a/builtin.c
+++ b/builtin.c
@@ -355,6 +355,62 @@ static struct symbol_op overflow_p_op = {
};
+static int eval_sync_compare_and_swap(struct expression *expr)
+{
+ struct symbol_list *types = NULL;
+ struct symbol *ctype = NULL;
+ struct expression *arg;
+ int n = 0;
+
+ /* the first arg is a pointer type; we'd already verified that */
+ FOR_EACH_PTR(expr->args, arg) {
+ struct symbol *t = arg->ctype;
+
+ 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) {
+ if (t->type == SYM_NODE)
+ t = t->ctype.base_type;
+ if (!t)
+ return 0;
+ if (t->type != SYM_PTR)
+ goto err;
+ t = t->ctype.base_type;
+ if (!t)
+ return 0;
+ if (t->type == SYM_NODE)
+ t = t->ctype.base_type;
+ if (!t)
+ return 0;
+ 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);
+ }
+ } END_FOR_EACH_PTR(arg);
+
+ if (!expr->ctype) // __sync_val_compare_and_swap()
+ expr->ctype = ctype;
+ return evaluate_arguments(types, expr->args);
+
+err:
+ sparse_error(arg->pos, "invalid type for argument %d:", n);
+ info(arg->pos, " %s", show_typename(arg->ctype));
+ expr->ctype = &bad_ctype;
+ return 0;
+}
+
+static struct symbol_op sync_compare_and_swap_op = {
+ .args = args_triadic,
+ .evaluate = eval_sync_compare_and_swap,
+};
+
+
/*
* Builtin functions
*/
@@ -548,7 +604,7 @@ static const struct builtin_fn builtins_common[] = {
{ "__sync_add_and_fetch", &int_ctype, 1, { &ptr_ctype }},
{ "__sync_and_and_fetch", &int_ctype, 1, { &ptr_ctype }},
- { "__sync_bool_compare_and_swap", &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 }},
@@ -561,7 +617,7 @@ static const struct builtin_fn builtins_common[] = {
{ "__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", &int_ctype, 1, { &ptr_ctype }},
+ { "__sync_val_compare_and_swap", NULL, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op },
{ "__sync_xor_and_fetch", &int_ctype, 1, { &ptr_ctype }},
{ }
diff --git a/dissect.c b/dissect.c
index 1970e46f..582e8fc3 100644
--- a/dissect.c
+++ b/dissect.c
@@ -204,9 +204,9 @@ static void examine_sym_node(struct symbol *node, struct symbol *parent)
struct ident *name = node->ident;
struct symbol *base, *dctx;
- if (node->examined)
+ if (node->visited)
return;
- node->examined = 1;
+ node->visited = 1;
node->kind = 'v';
while ((base = node->ctype.base_type) != NULL)
@@ -228,9 +228,9 @@ static void examine_sym_node(struct symbol *node, struct symbol *parent)
break;
case SYM_STRUCT: case SYM_UNION: //case SYM_ENUM:
- if (base->evaluated)
+ if (base->inspected)
return;
- base->evaluated = 1;
+ base->inspected = 1;
base->kind = 's';
if (!base->symbol_list)
@@ -471,6 +471,17 @@ again:
} while ((expr = expr->down));
}
+ break; case EXPR_GENERIC: {
+ struct type_expression *map;
+
+ do_expression(U_VOID, expr->control);
+
+ for (map = expr->map; map; map = map->next)
+ ret = do_expression(mode, map->expr);
+ if (expr->def)
+ ret = do_expression(mode, expr->def);
+ }
+
break; case EXPR_SYMBOL:
ret = report_symbol(mode, expr);
}
diff --git a/evaluate.c b/evaluate.c
index dddea761..63a9390b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -102,9 +102,10 @@ static struct symbol *evaluate_string(struct expression *expr)
struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
struct expression *initstr = alloc_expression(expr->pos, EXPR_STRING);
unsigned int length = expr->string->length;
+ struct symbol *char_type = expr->wide ? wchar_ctype : &char_ctype;
sym->array_size = alloc_const_expression(expr->pos, length);
- sym->bit_size = bytes_to_bits(length);
+ sym->bit_size = length * char_type->bit_size;
sym->ctype.alignment = 1;
sym->string = 1;
sym->ctype.modifiers = MOD_STATIC;
@@ -117,10 +118,10 @@ static struct symbol *evaluate_string(struct expression *expr)
initstr->string = expr->string;
array->array_size = sym->array_size;
- array->bit_size = bytes_to_bits(length);
- array->ctype.alignment = 1;
+ array->bit_size = sym->bit_size;
+ array->ctype.alignment = char_type->ctype.alignment;
array->ctype.modifiers = MOD_STATIC;
- array->ctype.base_type = &char_ctype;
+ array->ctype.base_type = char_type;
array->examined = 1;
array->evaluated = 1;
@@ -405,7 +406,10 @@ static inline int is_string_type(struct symbol *type)
{
if (type->type == SYM_NODE)
type = type->ctype.base_type;
- return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type);
+ if (type->type != SYM_ARRAY)
+ return 0;
+ type = type->ctype.base_type;
+ return is_byte_type(type) || is_wchar_type(type);
}
static struct symbol *bad_expr_type(struct expression *expr)
@@ -1342,8 +1346,17 @@ static int evaluate_assign_op(struct expression *expr)
return 1;
} else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) {
// shifts do integer promotions, but that's it.
+ unrestrict(expr->left, tclass, &t);
+ target = integer_promotion(t);
+
unrestrict(expr->right, sclass, &s);
- target = integer_promotion(s);
+ source = integer_promotion(s);
+ expr->right = cast_to(expr->right, source);
+
+ // both gcc & clang seems to do this, so ...
+ if (target->bit_size > source->bit_size)
+ expr->right = cast_to(expr->right, &uint_ctype);
+
goto Cast;
} else if (!(sclass & TYPE_RESTRICT))
goto usual;
@@ -2333,14 +2346,13 @@ static struct symbol *evaluate_alignof(struct expression *expr)
return size_t_ctype;
}
-static int evaluate_arguments(struct symbol *fn, struct expression_list *head)
+int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *head)
{
struct expression *expr;
- struct symbol_list *argument_types = fn->arguments;
struct symbol *argtype;
int i = 1;
- PREPARE_PTR_LIST(argument_types, argtype);
+ PREPARE_PTR_LIST(argtypes, argtype);
FOR_EACH_PTR (head, expr) {
struct expression **p = THIS_ADDRESS(expr);
struct symbol *ctype, *target;
@@ -2760,7 +2772,6 @@ static struct expression *handle_scalar(struct expression *e, int nested)
static int handle_initializer(struct expression **ep, int nested,
int class, struct symbol *ctype, unsigned long mods)
{
- int is_string = is_string_type(ctype);
struct expression *e = *ep, *p;
struct symbol *type;
@@ -2794,7 +2805,7 @@ static int handle_initializer(struct expression **ep, int nested,
* pathologies, so we don't need anything fancy here.
*/
if (e->type == EXPR_INITIALIZER) {
- if (is_string) {
+ if (is_string_type(ctype)) {
struct expression *v = NULL;
int count = 0;
@@ -2815,7 +2826,7 @@ static int handle_initializer(struct expression **ep, int nested,
/* string */
if (is_string_literal(&e)) {
/* either we are doing array of char, or we'll have to dig in */
- if (is_string) {
+ if (is_string_type(ctype)) {
*ep = e;
goto String;
}
@@ -2840,10 +2851,12 @@ String:
*p = *e;
type = evaluate_expression(p);
if (ctype->bit_size != -1) {
- if (ctype->bit_size + bits_in_char < type->bit_size)
+ struct symbol *char_type = e->wide ? wchar_ctype : &char_ctype;
+ unsigned int size_with_null = ctype->bit_size + char_type->bit_size;
+ if (size_with_null < type->bit_size)
warning(e->pos,
"too long initializer-string for array of char");
- else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) {
+ else if (Winit_cstring && size_with_null == type->bit_size) {
warning(e->pos,
"too long initializer-string for array of char(no space for nul char)");
}
@@ -3149,7 +3162,7 @@ static struct symbol *evaluate_call(struct expression *expr)
if (!sym->op->args(expr))
return NULL;
} else {
- if (!evaluate_arguments(ctype, arglist))
+ if (!evaluate_arguments(ctype->arguments, arglist))
return NULL;
args = expression_list_size(expr->args);
fnargs = symbol_list_size(ctype->arguments);
@@ -3544,7 +3557,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 && expr->ctype != &void_ctype)
+ if (expr && !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/evaluate.h b/evaluate.h
index f68f7fb7..a16e9703 100644
--- a/evaluate.h
+++ b/evaluate.h
@@ -2,6 +2,7 @@
#define EVALUATE_H
struct expression;
+struct expression_list;
struct statement;
struct symbol;
struct symbol_list;
@@ -25,4 +26,10 @@ struct symbol *evaluate_statement(struct statement *stmt);
// @list: the list of the symbol to be evaluated
void evaluate_symbol_list(struct symbol_list *list);
+///
+// evaluate the arguments of a function
+// @argtypes: the list of the types in the prototype
+// @args: the list of the effective arguments
+int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *args);
+
#endif
diff --git a/expand.c b/expand.c
index b0789331..623b1800 100644
--- a/expand.c
+++ b/expand.c
@@ -170,22 +170,6 @@ Float:
expr->type = EXPR_FVALUE;
}
-static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count)
-{
- if (count < 0) {
- if (!Wshift_count_negative)
- return;
- warning(expr->pos, "shift count is negative (%lld)", count);
- return;
- }
- if (ctype->type == SYM_NODE)
- ctype = ctype->ctype.base_type;
-
- if (!Wshift_count_overflow)
- return;
- warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype));
-}
-
/* Return true if constant shift size is valid */
static bool check_shift_count(struct expression *expr, struct expression *right)
{
@@ -194,8 +178,6 @@ static bool check_shift_count(struct expression *expr, struct expression *right)
if (count >= 0 && count < ctype->bit_size)
return true;
- if (!conservative)
- warn_shift_count(expr, ctype, count);
return false;
}
diff --git a/expression.h b/expression.h
index 07fe8502..3e9e9d85 100644
--- a/expression.h
+++ b/expression.h
@@ -261,7 +261,6 @@ struct expression {
struct expression *control;
struct expression *def;
struct type_expression *map;
- struct expression *result;
};
};
};
diff --git a/inline.c b/inline.c
index a9597280..eceef8ba 100644
--- a/inline.c
+++ b/inline.c
@@ -274,6 +274,14 @@ static struct expression * copy_expression(struct expression *expr)
}
break;
}
+ case EXPR_GENERIC:
+ expr = dup_expression(expr);
+ expr->control = copy_expression(expr->control);
+ if (!evaluate_expression(expr))
+ return NULL;
+ expr = copy_expression(expr);
+ break;
+
default:
warning(expr->pos, "trying to copy expression type %d", expr->type);
}
diff --git a/lib.c b/lib.c
index dcbbb5b3..4bc5cd02 100644
--- a/lib.c
+++ b/lib.c
@@ -351,7 +351,7 @@ static struct symbol_list *sparse_file(const char *filename)
base_filename = filename;
// Tokenize the input stream
- token = tokenize(filename, fd, -1, NULL, includepath);
+ token = tokenize(NULL, filename, fd, NULL, includepath);
close(fd);
return sparse_tokenstream(token);
@@ -383,6 +383,8 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list
char **args;
struct symbol_list *list;
+ base_filename = "command-line";
+
// Initialize symbol stream first, so that we can add defines etc
init_symbols();
diff --git a/lib.h b/lib.h
index 5458fa71..b35debc8 100644
--- a/lib.h
+++ b/lib.h
@@ -44,6 +44,10 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
+#ifndef PATH_MAX
+#define PATH_MAX 4096 // Hurd doesn't define this
+#endif
+
struct position {
unsigned int type:6,
diff --git a/linearize.c b/linearize.c
index 49274681..5a8e7497 100644
--- a/linearize.c
+++ b/linearize.c
@@ -2468,6 +2468,49 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm
return VOID;
}
+static void check_tainted_insn(struct instruction *insn)
+{
+ unsigned long long uval;
+ long long sval;
+ pseudo_t src2;
+
+ switch (insn->opcode) {
+ case OP_DIVU: case OP_DIVS:
+ case OP_MODU: case OP_MODS:
+ if (insn->src2 == value_pseudo(0))
+ warning(insn->pos, "divide by zero");
+ break;
+ case OP_SHL: case OP_LSR: case OP_ASR:
+ src2 = insn->src2;
+ if (src2->type != PSEUDO_VAL)
+ break;
+ uval = src2->value;
+ if (uval < insn->size)
+ break;
+ sval = sign_extend(uval, insn->size);
+ if (Wshift_count_negative && sval < 0)
+ warning(insn->pos, "shift count is negative (%lld)", sval);
+ else if (Wshift_count_overflow)
+ warning(insn->pos, "shift too big (%llu) for type %s", uval, show_typename(insn->type));
+ }
+}
+
+///
+// issue warnings after all possible DCE
+static void late_warnings(struct entrypoint *ep)
+{
+ struct basic_block *bb;
+ FOR_EACH_PTR(ep->bbs, bb) {
+ struct instruction *insn;
+ FOR_EACH_PTR(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
+ if (insn->tainted)
+ check_tainted_insn(insn);
+ } END_FOR_EACH_PTR(insn);
+ } END_FOR_EACH_PTR(bb);
+}
+
static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type)
{
struct statement *stmt = base_type->stmt;
@@ -2514,6 +2557,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
add_one_insn(ep, ret);
optimize(ep);
+ late_warnings(ep);
return ep;
}
diff --git a/options.c b/options.c
index a2e15bb7..f7e81b84 100644
--- a/options.c
+++ b/options.c
@@ -782,6 +782,12 @@ static char **handle_switch_s(const char *arg, char **next)
static char **handle_switch_U(char *arg, char **next)
{
const char *name = arg + 1;
+
+ if (*name == '\0') {
+ name = *++next;
+ if (!name)
+ die("argument to `-U' is missing");
+ }
add_pre_buffer("#undef %s\n", name);
return next;
}
diff --git a/parse.c b/parse.c
index cc5dbd52..5f587ce6 100644
--- a/parse.c
+++ b/parse.c
@@ -171,7 +171,7 @@ static struct symbol_op register_op = {
};
static struct symbol_op static_op = {
- .type = KW_MODIFIER,
+ .type = KW_MODIFIER|KW_STATIC,
.declarator = static_specifier,
};
@@ -678,24 +678,6 @@ static void fn_local_symbol(struct symbol *sym)
add_symbol(function_symbol_list, sym);
}
-static int SENTINEL_ATTR match_idents(struct token *token, ...)
-{
- va_list args;
- struct ident * next;
-
- if (token_type(token) != TOKEN_IDENT)
- return 0;
-
- va_start(args, token);
- do {
- next = va_arg(args, struct ident *);
- } while (next && token->ident != next);
- va_end(args);
-
- return next && token->ident == next;
-}
-
-
struct statement *alloc_statement(struct position pos, int type)
{
struct statement *stmt = __alloc_statement(0);
@@ -1362,18 +1344,8 @@ static struct token *attribute_specifier(struct token *token, struct decl_state
token = expect(token, '(', "after attribute");
token = expect(token, '(', "after attribute");
- for (;;) {
- struct ident *attribute_name;
- struct symbol *attr;
-
- if (eof_token(token))
- break;
- if (match_op(token, ';'))
- break;
- if (token_type(token) != TOKEN_IDENT)
- break;
- attribute_name = token->ident;
- attr = lookup_keyword(attribute_name, NS_KEYWORD);
+ while (token_type(token) == TOKEN_IDENT) {
+ struct symbol *attr = lookup_keyword(token->ident, NS_KEYWORD);
if (attr && attr->op->attribute)
token = attr->op->attribute(token->next, attr, ctx);
else
@@ -1721,29 +1693,26 @@ static struct token *declaration_specifiers(struct token *token, struct decl_sta
return token;
}
-static struct token *abstract_array_static_declarator(struct token *token, int *has_static)
-{
- while (token->ident == &static_ident) {
- if (*has_static)
- sparse_error(token->pos, "duplicate array static declarator");
-
- *has_static = 1;
- token = token->next;
- }
- return token;
-
-}
-
static struct token *abstract_array_declarator(struct token *token, struct symbol *sym)
{
struct expression *expr = NULL;
int has_static = 0;
- token = abstract_array_static_declarator(token, &has_static);
-
- if (match_idents(token, &restrict_ident, &__restrict_ident, &__restrict___ident, NULL))
- token = abstract_array_static_declarator(token->next, &has_static);
- token = parse_expression(token, &expr);
+ while (token_type(token) == TOKEN_IDENT) {
+ struct symbol *sym = lookup_keyword(token->ident, NS_TYPEDEF);
+ if (!sym || !(sym->op->type & (KW_STATIC|KW_QUALIFIER)))
+ break;
+ if (has_static && (sym->op->type & KW_STATIC))
+ sparse_error(token->pos, "duplicate array static declarator");
+ has_static |= (sym->op->type & KW_STATIC);
+ token = token->next;
+ }
+ if (match_op(token, '*') && match_op(token->next, ']')) {
+ // FIXME: '[*]' is treated like '[]'
+ token = token->next;
+ } else {
+ token = assignment_expression(token, &expr);
+ }
sym->array_size = expr;
return token;
}
@@ -1784,13 +1753,7 @@ static struct token *skip_attributes(struct token *token)
break;
token = expect(token->next, '(', "after attribute");
token = expect(token, '(', "after attribute");
- for (;;) {
- if (eof_token(token))
- break;
- if (match_op(token, ';'))
- break;
- if (token_type(token) != TOKEN_IDENT)
- break;
+ while (token_type(token) == TOKEN_IDENT) {
token = skip_attribute(token);
if (!match_op(token, ','))
break;
diff --git a/pre-process.c b/pre-process.c
index 6f4bf897..7a1478f6 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -890,10 +890,6 @@ 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(struct position pos, const char *path, const char *filename, int flen, struct token **where, const char **next_path)
{
int fd;
@@ -911,7 +907,7 @@ static int try_include(struct position pos, const char *path, const char *filena
fd = open(fullname, O_RDONLY);
if (fd >= 0) {
char *streamname = xmemdup(fullname, plen + flen);
- *where = tokenize(streamname, fd, pos.stream, *where, next_path);
+ *where = tokenize(&pos, streamname, fd, *where, next_path);
close(fd);
return 1;
}
@@ -2091,7 +2087,7 @@ static void create_arglist(struct symbol *sym, int count)
static void init_preprocessor(void)
{
int i;
- int stream = init_stream("preprocessor", -1, includepath, -1);
+ int stream = init_stream(NULL, "preprocessor", -1, includepath);
static struct {
const char *name;
int (*handler)(struct stream *, struct token **, struct token *);
diff --git a/sindex.1 b/semind.1
index e3e14ca3..44e79346 100644
--- a/sindex.1
+++ b/semind.1
@@ -1,27 +1,27 @@
.\" Sindex manpage by Alexey Gladkov
-.TH sindex "1"
+.TH semind "1"
.
.SH NAME
-sindex \- Semantic Indexer for C
+semind \- Semantic Indexer for C
.
.SH SYNOPSIS
-.B sindex
+.B semind
[\fIoptions\fR]
.br
-.B sindex
+.B semind
[\fIoptions\fR] \fIadd\fR [\fIcommand options\fR] [\fI--\fR] [\fIcompiler options\fR] [\fIfiles...\fR]
.br
-.B sindex
+.B semind
[\fIoptions\fR] \fIrm\fR [\fIcommand options\fR] \fIpattern\fR
.br
-.B sindex
+.B semind
[\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] [\fIpattern\fR]
.br
-.B sindex [\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] (\fI-e\fR|\fI-l\fR) \fIfilename\fR:\fIlinenr\fR:\fIcolumn\fR
+.B semind [\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] (\fI-e\fR|\fI-l\fR) \fIfilename\fR:\fIlinenr\fR:\fIcolumn\fR
.br
.SH DESCRIPTION
.P
-sindex is the simple to use cscope-like tool based on sparse/dissect. Unlike
+semind is the simple to use cscope-like tool based on sparse/dissect. Unlike
cscope it runs after pre-processor and thus it can't index the code filtered out
by ifdef's, but otoh it understands how the symbol is used and it can track the
usage of struct members.
@@ -44,7 +44,7 @@ wildcard pattern.
.SH COMMON OPTIONS
.TP
\fB-D\fR, \fB--database=FILE\fR
-specify database file (default: ./sindex.sqlite).
+specify database file (default: ./semind.sqlite).
.TP
\fB-v\fR, \fB--verbose\fR
show information about what is being done.
@@ -128,8 +128,8 @@ struct member
.
.SH MODE
The \fBMODE\fR is dumped as a 3-letter string. The first letter denotes address
-of part, 2-nd - access by value, 3-rd - access by pointer. A special value
-\'\fIdef\fR\' means a symbol definition.
+of part, 2-nd - access by value, 3-rd - access by pointer. A special
+value '\fIdef\fR' means a symbol definition.
.TP
\fBr\fR
read
@@ -144,7 +144,7 @@ read and write
.BR sparse (1)
.
.SH HOMEPAGE
-http://www.kernel.org/pub/software/devel/sparse/
+https://sparse.docs.kernel.org
.
.SH MAILING LIST
linux-sparse@vger.kernel.org
diff --git a/sindex.c b/semind.c
index 22836a95..911fc747 100644
--- a/sindex.c
+++ b/semind.c
@@ -1,5 +1,5 @@
/*
- * sindex - semantic indexer for C.
+ * semind - semantic indexer for C.
*
* Copyright (C) 2020 Alexey Gladkov
*/
@@ -23,44 +23,44 @@
#define U_DEF (0x100 << U_SHIFT)
#define SINDEX_DATABASE_VERSION 1
-#define message(fmt, ...) sindex_error(0, 0, (fmt), ##__VA_ARGS__)
+#define message(fmt, ...) semind_error(0, 0, (fmt), ##__VA_ARGS__)
static const char *progname;
-static const char *sindex_command = NULL;
+static const char *semind_command = NULL;
// common options
-static const char *sindex_dbfile = "sindex.sqlite";
-static int sindex_verbose = 0;
+static const char *semind_dbfile = "semind.sqlite";
+static int semind_verbose = 0;
static char cwd[PATH_MAX];
static size_t n_cwd;
// 'add' command options
-static struct string_list *sindex_filelist = NULL;
-static int sindex_include_local_syms = 0;
+static struct string_list *semind_filelist = NULL;
+static int semind_include_local_syms = 0;
-struct sindex_streams {
+struct semind_streams {
sqlite3_int64 id;
};
-static struct sindex_streams *sindex_streams = NULL;
-static int sindex_streams_nr = 0;
+static struct semind_streams *semind_streams = NULL;
+static int semind_streams_nr = 0;
// 'search' command options
-static int sindex_search_modmask;
-static int sindex_search_modmask_defined = 0;
-static int sindex_search_kind = 0;
-static char *sindex_search_path = NULL;
-static char *sindex_search_symbol = NULL;
-static const char *sindex_search_format = "(%m) %f\t%l\t%c\t%C\t%s";
+static int semind_search_modmask;
+static int semind_search_modmask_defined = 0;
+static int semind_search_kind = 0;
+static char *semind_search_path = NULL;
+static char *semind_search_symbol = NULL;
+static const char *semind_search_format = "(%m) %f\t%l\t%c\t%C\t%s";
#define EXPLAIN_LOCATION 1
#define USAGE_BY_LOCATION 2
-static int sindex_search_by_location;
-static char *sindex_search_filename;
-static int sindex_search_line;
-static int sindex_search_column;
+static int semind_search_by_location;
+static char *semind_search_filename;
+static int semind_search_line;
+static int semind_search_column;
-static sqlite3 *sindex_db = NULL;
+static sqlite3 *semind_db = NULL;
static sqlite3_stmt *lock_stmt = NULL;
static sqlite3_stmt *unlock_stmt = NULL;
static sqlite3_stmt *insert_rec_stmt = NULL;
@@ -77,9 +77,9 @@ struct command {
static void show_usage(void)
{
- if (sindex_command)
+ if (semind_command)
printf("Try '%s %s --help' for more information.\n",
- progname, sindex_command);
+ progname, semind_command);
else
printf("Try '%s --help' for more information.\n",
progname);
@@ -101,15 +101,17 @@ static void show_help(int ret)
"\n"
"Options:\n"
" -D, --database=FILE Specify database file (default: %2$s);\n"
+ " -B, --basedir=DIR Define project top directory (default is the current directory);\n"
" -v, --verbose Show information about what is being done;\n"
" -h, --help Show this text and exit.\n"
"\n"
"Environment:\n"
" SINDEX_DATABASE Database file location.\n"
+ " SINDEX_BASEDIR Project top directory.\n"
"\n"
"Report bugs to authors.\n"
"\n",
- progname, sindex_dbfile);
+ progname, semind_dbfile);
exit(ret);
}
@@ -125,9 +127,6 @@ static void show_help_add(int ret)
" -v, --verbose Show information about what is being done;\n"
" -h, --help Show this text and exit.\n"
"\n"
- "Environment:\n"
- " SINDEX_BASEDIRE Project top directory.\n"
- "\n"
"Report bugs to authors.\n"
"\n",
progname);
@@ -180,17 +179,17 @@ static void show_help_search(int ret)
exit(ret);
}
-static void sindex_print_progname(void)
+static void semind_print_progname(void)
{
fprintf(stderr, "%s: ", progname);
- if (sindex_command)
- fprintf(stderr, "%s: ", sindex_command);
+ if (semind_command)
+ fprintf(stderr, "%s: ", semind_command);
}
-static void sindex_error(int status, int errnum, const char *fmt, ...)
+static void semind_error(int status, int errnum, const char *fmt, ...)
{
va_list ap;
- sindex_print_progname();
+ semind_print_progname();
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
@@ -210,10 +209,10 @@ static void set_search_modmask(const char *v)
size_t n = strlen(v);
if (n != 1 && n != 3)
- sindex_error(1, 0, "the length of mode value must be 1 or 3: %s", v);
+ semind_error(1, 0, "the length of mode value must be 1 or 3: %s", v);
- sindex_search_modmask_defined = 1;
- sindex_search_modmask = 0;
+ semind_search_modmask_defined = 1;
+ semind_search_modmask = 0;
if (n == 1) {
switch (v[0]) {
@@ -221,10 +220,10 @@ static void set_search_modmask(const char *v)
case 'w': v = "ww-"; break;
case 'm': v = "mmm"; break;
case '-': v = "---"; break;
- default: sindex_error(1, 0, "unknown modificator: %s", v);
+ default: semind_error(1, 0, "unknown modificator: %s", v);
}
} else if (!strcmp(v, "def")) {
- sindex_search_modmask = U_DEF;
+ semind_search_modmask = U_DEF;
return;
}
@@ -236,11 +235,11 @@ static void set_search_modmask(const char *v)
for (int i = 0; i < 3; i++) {
switch (v[i]) {
- case 'r': sindex_search_modmask |= modes[i * 3]; break;
- case 'w': sindex_search_modmask |= modes[i * 3 + 1]; break;
- case 'm': sindex_search_modmask |= modes[i * 3 + 2]; break;
+ case 'r': semind_search_modmask |= modes[i * 3]; break;
+ case 'w': semind_search_modmask |= modes[i * 3 + 1]; break;
+ case 'm': semind_search_modmask |= modes[i * 3 + 2]; break;
case '-': break;
- default: sindex_error(1, 0,
+ default: semind_error(1, 0,
"unknown modificator in the mode value"
" (`r', `w', `m' or `-' expected): %c", v[i]);
}
@@ -251,23 +250,28 @@ static void parse_cmdline(int argc, char **argv)
{
static const struct option long_options[] = {
{ "database", required_argument, NULL, 'D' },
+ { "basedir", required_argument, NULL, 'B' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ NULL }
};
int c;
+ char *basedir = getenv("SINDEX_BASEDIR");
char *env;
if ((env = getenv("SINDEX_DATABASE")) != NULL)
- sindex_dbfile = env;
+ semind_dbfile = env;
- while ((c = getopt_long(argc, argv, "+D:vh", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "+B:D:vh", long_options, NULL)) != -1) {
switch (c) {
case 'D':
- sindex_dbfile = optarg;
+ semind_dbfile = optarg;
+ break;
+ case 'B':
+ basedir = optarg;
break;
case 'v':
- sindex_verbose++;
+ semind_verbose++;
break;
case 'h':
show_help(0);
@@ -278,6 +282,12 @@ static void parse_cmdline(int argc, char **argv)
message("command required");
show_usage();
}
+
+ if (basedir) {
+ if (!realpath(basedir, cwd))
+ semind_error(1, errno, "unable to get project base directory");
+ n_cwd = strlen(cwd);
+ }
}
static void parse_cmdline_add(int argc, char **argv)
@@ -295,10 +305,10 @@ static void parse_cmdline_add(int argc, char **argv)
while ((c = getopt_long(argc, argv, "+vh", long_options, NULL)) != -1) {
switch (c) {
case 1:
- sindex_include_local_syms = 1;
+ semind_include_local_syms = 1;
break;
case 'v':
- sindex_verbose++;
+ semind_verbose++;
break;
case 'h':
show_help_add(0);
@@ -318,7 +328,7 @@ done:
// step back since sparse_initialize will ignore argv[0].
optind--;
- sparse_initialize(argc - optind, argv + optind, &sindex_filelist);
+ sparse_initialize(argc - optind, argv + optind, &semind_filelist);
}
static void parse_cmdline_rm(int argc, char **argv)
@@ -333,7 +343,7 @@ static void parse_cmdline_rm(int argc, char **argv)
while ((c = getopt_long(argc, argv, "+vh", long_options, NULL)) != -1) {
switch (c) {
case 'v':
- sindex_verbose++;
+ semind_verbose++;
break;
case 'h':
show_help_rm(0);
@@ -364,36 +374,36 @@ static void parse_cmdline_search(int argc, char **argv)
while ((c = getopt_long(argc, argv, "+ef:m:k:p:lvh", long_options, NULL)) != -1) {
switch (c) {
case 'e':
- sindex_search_by_location = EXPLAIN_LOCATION;
+ semind_search_by_location = EXPLAIN_LOCATION;
break;
case 'l':
- sindex_search_by_location = USAGE_BY_LOCATION;
+ semind_search_by_location = USAGE_BY_LOCATION;
break;
case 'f':
- sindex_search_format = optarg;
+ semind_search_format = optarg;
break;
case 'm':
set_search_modmask(optarg);
break;
case 'k':
- sindex_search_kind = tolower(optarg[0]);
+ semind_search_kind = tolower(optarg[0]);
break;
case 'p':
- sindex_search_path = optarg;
+ semind_search_path = optarg;
break;
case 'v':
- sindex_verbose++;
+ semind_verbose++;
break;
case 'h':
show_help_search(0);
}
}
- if (sindex_search_by_location) {
+ if (semind_search_by_location) {
char *str;
if (optind == argc)
- sindex_error(1, 0, "one argument required");
+ semind_error(1, 0, "one argument required");
str = argv[optind];
@@ -404,18 +414,18 @@ static void parse_cmdline_search(int argc, char **argv)
*ptr++ = '\0';
if (*str != '\0') {
- if (!sindex_search_filename) {
- sindex_search_filename = str;
- } else if (!sindex_search_line) {
- sindex_search_line = atoi(str);
- } else if (!sindex_search_column) {
- sindex_search_column = atoi(str);
+ if (!semind_search_filename) {
+ semind_search_filename = str;
+ } else if (!semind_search_line) {
+ semind_search_line = atoi(str);
+ } else if (!semind_search_column) {
+ semind_search_column = atoi(str);
}
}
str = ptr;
}
} else if (optind < argc)
- sindex_search_symbol = argv[optind++];
+ semind_search_symbol = argv[optind++];
}
static int query_appendf(sqlite3_str *query, const char *fmt, ...)
@@ -442,22 +452,22 @@ static int query_appendf(sqlite3_str *query, const char *fmt, ...)
static inline void sqlite_bind_text(sqlite3_stmt *stmt, const char *field, const char *var, int len)
{
if (sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, field), var, len, SQLITE_STATIC) != SQLITE_OK)
- sindex_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(sindex_db));
+ semind_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(semind_db));
}
static inline void sqlite_bind_int64(sqlite3_stmt *stmt, const char *field, long long var)
{
if (sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, field), var) != SQLITE_OK)
- sindex_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(sindex_db));
+ semind_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(semind_db));
}
static inline void sqlite_prepare(const char *sql, sqlite3_stmt **stmt)
{
int ret;
do {
- ret = sqlite3_prepare_v2(sindex_db, sql, -1, stmt, NULL);
+ ret = sqlite3_prepare_v2(semind_db, sql, -1, stmt, NULL);
if (ret != SQLITE_OK && ret != SQLITE_BUSY)
- sindex_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(sindex_db), sql);
+ semind_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(semind_db), sql);
} while (ret == SQLITE_BUSY);
}
@@ -465,9 +475,9 @@ static inline void sqlite_prepare_persistent(const char *sql, sqlite3_stmt **stm
{
int ret;
do {
- ret = sqlite3_prepare_v3(sindex_db, sql, -1, SQLITE_PREPARE_PERSISTENT, stmt, NULL);
+ ret = sqlite3_prepare_v3(semind_db, sql, -1, SQLITE_PREPARE_PERSISTENT, stmt, NULL);
if (ret != SQLITE_OK && ret != SQLITE_BUSY)
- sindex_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(sindex_db), sql);
+ semind_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(semind_db), sql);
} while (ret == SQLITE_BUSY);
}
@@ -484,7 +494,7 @@ static int sqlite_run(sqlite3_stmt *stmt)
{
int ret = sqlite3_step(stmt);
if (ret != SQLITE_DONE && ret != SQLITE_ROW)
- sindex_error(1, 0, "unable to process query: %s: %s", sqlite3_errmsg(sindex_db), sqlite3_sql(stmt));
+ semind_error(1, 0, "unable to process query: %s: %s", sqlite3_errmsg(semind_db), sqlite3_sql(stmt));
return ret;
}
@@ -512,7 +522,7 @@ static sqlite3_int64 get_db_version(void)
static void set_db_version(void)
{
char *sql;
- sqlite3_str *query = sqlite3_str_new(sindex_db);
+ sqlite3_str *query = sqlite3_str_new(semind_db);
if (query_appendf(query, "PRAGMA user_version = %d", SINDEX_DATABASE_VERSION) < 0)
exit(1);
@@ -526,7 +536,7 @@ static void open_temp_database(void)
{
static const char *database_schema[] = {
"ATTACH ':memory:' AS tempdb",
- "CREATE TABLE tempdb.sindex ("
+ "CREATE TABLE tempdb.semind ("
" file INTEGER NOT NULL,"
" line INTEGER NOT NULL,"
" column INTEGER NOT NULL,"
@@ -550,7 +560,7 @@ static void open_database(const char *filename, int flags)
" name TEXT UNIQUE NOT NULL,"
" mtime INTEGER NOT NULL"
")",
- "CREATE TABLE sindex ("
+ "CREATE TABLE semind ("
" file INTEGER NOT NULL REFERENCES file(id) ON DELETE CASCADE,"
" line INTEGER NOT NULL,"
" column INTEGER NOT NULL,"
@@ -559,15 +569,15 @@ static void open_database(const char *filename, int flags)
" context TEXT,"
" mode INTEGER NOT NULL"
")",
- "CREATE UNIQUE INDEX sindex_0 ON sindex (symbol, kind, mode, file, line, column)",
- "CREATE INDEX sindex_1 ON sindex (file)",
+ "CREATE UNIQUE INDEX semind_0 ON semind (symbol, kind, mode, file, line, column)",
+ "CREATE INDEX semind_1 ON semind (file)",
NULL,
};
int exists = !access(filename, R_OK);
- if (sqlite3_open_v2(filename, &sindex_db, flags, NULL) != SQLITE_OK)
- sindex_error(1, 0, "unable to open database: %s: %s", filename, sqlite3_errmsg(sindex_db));
+ if (sqlite3_open_v2(filename, &semind_db, flags, NULL) != SQLITE_OK)
+ semind_error(1, 0, "unable to open database: %s: %s", filename, sqlite3_errmsg(semind_db));
sqlite_command("PRAGMA journal_mode = WAL");
sqlite_command("PRAGMA synchronous = OFF");
@@ -577,7 +587,7 @@ static void open_database(const char *filename, int flags)
if (exists) {
if (get_db_version() < SINDEX_DATABASE_VERSION)
- sindex_error(1, 0, "%s: Database too old. Please rebuild it.", filename);
+ semind_error(1, 0, "%s: Database too old. Please rebuild it.", filename);
return;
}
@@ -617,16 +627,16 @@ static void insert_record(struct index_record *rec)
static void update_stream(void)
{
- if (sindex_streams_nr >= input_stream_nr)
+ if (semind_streams_nr >= input_stream_nr)
return;
- sindex_streams = realloc(sindex_streams, input_stream_nr * sizeof(struct sindex_streams));
- if (!sindex_streams)
- sindex_error(1, errno, "realloc");
+ semind_streams = realloc(semind_streams, input_stream_nr * sizeof(struct semind_streams));
+ if (!semind_streams)
+ semind_error(1, errno, "realloc");
sqlite_run(lock_stmt);
- for (int i = sindex_streams_nr; i < input_stream_nr; i++) {
+ for (int i = semind_streams_nr; i < input_stream_nr; i++) {
struct stat st;
const char *filename;
char fullname[PATH_MAX];
@@ -637,26 +647,26 @@ static void update_stream(void)
* FIXME: Files in the input_streams may be duplicated.
*/
if (stat(input_streams[i].name, &st) < 0)
- sindex_error(1, errno, "stat: %s", input_streams[i].name);
+ semind_error(1, errno, "stat: %s", input_streams[i].name);
cur_mtime = st.st_mtime;
if (!realpath(input_streams[i].name, fullname))
- sindex_error(1, errno, "realpath: %s", input_streams[i].name);
+ semind_error(1, errno, "realpath: %s", input_streams[i].name);
if (!strncmp(fullname, cwd, n_cwd) && fullname[n_cwd] == '/') {
filename = fullname + n_cwd + 1;
- sindex_streams[i].id = 0;
+ semind_streams[i].id = 0;
} else {
- sindex_streams[i].id = -1;
+ semind_streams[i].id = -1;
continue;
}
} else {
- sindex_streams[i].id = -1;
+ semind_streams[i].id = -1;
continue;
}
- if (sindex_verbose > 1)
+ if (semind_verbose > 1)
message("filename: %s", filename);
sqlite_bind_text(select_file_stmt, "@name", filename, -1);
@@ -664,7 +674,7 @@ static void update_stream(void)
if (sqlite_run(select_file_stmt) == SQLITE_ROW) {
sqlite3_int64 old_mtime;
- sindex_streams[i].id = sqlite3_column_int64(select_file_stmt, 0);
+ semind_streams[i].id = sqlite3_column_int64(select_file_stmt, 0);
old_mtime = sqlite3_column_int64(select_file_stmt, 1);
sqlite_reset_stmt(select_file_stmt);
@@ -684,12 +694,12 @@ static void update_stream(void)
sqlite_run(insert_file_stmt);
sqlite_reset_stmt(insert_file_stmt);
- sindex_streams[i].id = sqlite3_last_insert_rowid(sindex_db);
+ semind_streams[i].id = sqlite3_last_insert_rowid(semind_db);
}
sqlite_run(unlock_stmt);
- sindex_streams_nr = input_stream_nr;
+ semind_streams_nr = input_stream_nr;
}
static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym)
@@ -700,10 +710,10 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym)
update_stream();
- if (sindex_streams[pos->stream].id == -1)
+ if (semind_streams[pos->stream].id == -1)
return;
- if (!sindex_include_local_syms && sym_is_local(sym))
+ if (!semind_include_local_syms && sym_is_local(sym))
return;
if (!sym->ident) {
@@ -720,7 +730,7 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym)
rec.sym_len = sym->ident->len;
rec.kind = sym->kind;
rec.mode = mode;
- rec.file = sindex_streams[pos->stream].id;
+ rec.file = semind_streams[pos->stream].id;
rec.line = pos->line;
rec.col = pos->pos;
@@ -737,10 +747,10 @@ static void r_member(unsigned mode, struct position *pos, struct symbol *sym, st
update_stream();
- if (sindex_streams[pos->stream].id == -1)
+ if (semind_streams[pos->stream].id == -1)
return;
- if (!sindex_include_local_syms && sym_is_local(sym))
+ if (!semind_include_local_syms && sym_is_local(sym))
return;
ni = built_in_ident("?");
@@ -759,7 +769,7 @@ static void r_member(unsigned mode, struct position *pos, struct symbol *sym, st
rec.sym_len = si->len + mi->len + 1;
rec.kind = 'm';
rec.mode = mode;
- rec.file = sindex_streams[pos->stream].id;
+ rec.file = semind_streams[pos->stream].id;
rec.line = pos->line;
rec.col = pos->pos;
@@ -796,7 +806,7 @@ static void command_add(int argc, char **argv)
&unlock_stmt);
sqlite_prepare_persistent(
- "INSERT OR IGNORE INTO tempdb.sindex "
+ "INSERT OR IGNORE INTO tempdb.semind "
"(context, symbol, kind, mode, file, line, column) "
"VALUES (@context, @symbol, @kind, @mode, @file, @line, @column)",
&insert_rec_stmt);
@@ -813,10 +823,10 @@ static void command_add(int argc, char **argv)
"DELETE FROM file WHERE name == @name",
&delete_file_stmt);
- dissect(&reporter, sindex_filelist);
+ dissect(&reporter, semind_filelist);
sqlite_run(lock_stmt);
- sqlite_command("INSERT OR IGNORE INTO sindex SELECT * FROM tempdb.sindex");
+ sqlite_command("INSERT OR IGNORE INTO semind SELECT * FROM tempdb.semind");
sqlite_run(unlock_stmt);
sqlite3_finalize(insert_rec_stmt);
@@ -825,7 +835,7 @@ static void command_add(int argc, char **argv)
sqlite3_finalize(delete_file_stmt);
sqlite3_finalize(lock_stmt);
sqlite3_finalize(unlock_stmt);
- free(sindex_streams);
+ free(semind_streams);
}
static void command_rm(int argc, char **argv)
@@ -835,7 +845,7 @@ static void command_rm(int argc, char **argv)
sqlite_command("BEGIN IMMEDIATE");
sqlite_prepare("DELETE FROM file WHERE name GLOB @file", &stmt);
- if (sindex_verbose > 1)
+ if (semind_verbose > 1)
message("SQL: %s", sqlite3_sql(stmt));
for (int i = 0; i < argc; i++) {
@@ -867,12 +877,12 @@ static inline void print_mode(char *value)
#undef U
}
-static char *sindex_file_name;
-static FILE *sindex_file_fd;
-static int sindex_file_lnum;
-static char *sindex_line;
-static size_t sindex_line_buflen;
-static int sindex_line_len;
+static char *semind_file_name;
+static FILE *semind_file_fd;
+static int semind_file_lnum;
+static char *semind_line;
+static size_t semind_line_buflen;
+static int semind_line_len;
static void print_file_line(const char *name, int lnum)
{
@@ -880,43 +890,43 @@ static void print_file_line(const char *name, int lnum)
* All files are sorted by name and line number. So, we can reopen
* the file and read it line by line.
*/
- if (!sindex_file_name || strcmp(sindex_file_name, name)) {
- if (sindex_file_fd) {
- fclose(sindex_file_fd);
- free(sindex_file_name);
+ if (!semind_file_name || strcmp(semind_file_name, name)) {
+ if (semind_file_fd) {
+ fclose(semind_file_fd);
+ free(semind_file_name);
}
- sindex_file_name = strdup(name);
+ semind_file_name = strdup(name);
- if (!sindex_file_name)
- sindex_error(1, errno, "strdup");
+ if (!semind_file_name)
+ semind_error(1, errno, "strdup");
- sindex_file_fd = fopen(name, "r");
+ semind_file_fd = fopen(name, "r");
- if (!sindex_file_fd)
- sindex_error(1, errno, "fopen: %s", name);
+ if (!semind_file_fd)
+ semind_error(1, errno, "fopen: %s", name);
- sindex_file_lnum = 0;
+ semind_file_lnum = 0;
}
do {
- if (sindex_file_lnum == lnum) {
- if (sindex_line[sindex_line_len-1] == '\n')
- sindex_line_len--;
- printf("%.*s", sindex_line_len, sindex_line);
+ if (semind_file_lnum == lnum) {
+ if (semind_line[semind_line_len-1] == '\n')
+ semind_line_len--;
+ printf("%.*s", semind_line_len, semind_line);
break;
}
- sindex_file_lnum++;
+ semind_file_lnum++;
errno = 0;
- } while((sindex_line_len = getline(&sindex_line, &sindex_line_buflen, sindex_file_fd)) != -1);
+ } while((semind_line_len = getline(&semind_line, &semind_line_buflen, semind_file_fd)) != -1);
if (errno && errno != EOF)
- sindex_error(1, errno, "getline");
+ semind_error(1, errno, "getline");
}
static int search_query_callback(void *data, int argc, char **argv, char **colname)
{
- char *fmt = (char *) sindex_search_format;
+ char *fmt = (char *) semind_search_format;
char buf[32];
int quote = 0;
int n = 0;
@@ -938,7 +948,7 @@ static int search_query_callback(void *data, int argc, char **argv, char **colna
c = *fmt;
if (c == '\0')
- sindex_error(1, 0, "unexpected end of format string");
+ semind_error(1, 0, "unexpected end of format string");
switch (c) {
case 'f': colnum = 0; goto print_string;
@@ -985,7 +995,7 @@ static int search_query_callback(void *data, int argc, char **argv, char **colna
}
if (pos == fmt)
- sindex_error(1, 0, "invalid format specification: %%%c", c);
+ semind_error(1, 0, "invalid format specification: %%%c", c);
continue;
} else if (c == '\\') {
@@ -1014,101 +1024,104 @@ static void command_search(int argc, char **argv)
{
char *sql;
char *dberr = NULL;
- sqlite3_str *query = sqlite3_str_new(sindex_db);
+ sqlite3_str *query = sqlite3_str_new(semind_db);
+
+ if (chdir(cwd) < 0)
+ semind_error(1, errno, "unable to change directory: %s", cwd);
if (query_appendf(query,
"SELECT"
" file.name,"
- " sindex.line,"
- " sindex.column,"
- " sindex.context,"
- " sindex.symbol,"
- " sindex.mode,"
- " sindex.kind "
- "FROM sindex, file "
- "WHERE sindex.file == file.id") < 0)
+ " semind.line,"
+ " semind.column,"
+ " semind.context,"
+ " semind.symbol,"
+ " semind.mode,"
+ " semind.kind "
+ "FROM semind, file "
+ "WHERE semind.file == file.id") < 0)
goto fail;
- if (sindex_search_kind) {
- if (query_appendf(query, " AND sindex.kind == %d", sindex_search_kind) < 0)
+ if (semind_search_kind) {
+ if (query_appendf(query, " AND semind.kind == %d", semind_search_kind) < 0)
goto fail;
}
- if (sindex_search_symbol) {
+ if (semind_search_symbol) {
int ret;
if (query_appendf(query, " AND ") < 0)
goto fail;
- if (strpbrk(sindex_search_symbol, "*?[]"))
- ret = query_appendf(query, "sindex.symbol GLOB %Q", sindex_search_symbol);
+ if (strpbrk(semind_search_symbol, "*?[]"))
+ ret = query_appendf(query, "semind.symbol GLOB %Q", semind_search_symbol);
else
- ret = query_appendf(query, "sindex.symbol == %Q", sindex_search_symbol);
+ ret = query_appendf(query, "semind.symbol == %Q", semind_search_symbol);
if (ret < 0)
goto fail;
}
- if (sindex_search_modmask_defined) {
- if (!sindex_search_modmask) {
- if (query_appendf(query, " AND sindex.mode == %d", sindex_search_modmask) < 0)
+ if (semind_search_modmask_defined) {
+ if (!semind_search_modmask) {
+ if (query_appendf(query, " AND semind.mode == %d", semind_search_modmask) < 0)
goto fail;
- } else if (query_appendf(query, " AND (sindex.mode & %d) != 0", sindex_search_modmask) < 0)
+ } else if (query_appendf(query, " AND (semind.mode & %d) != 0", semind_search_modmask) < 0)
goto fail;
}
- if (sindex_search_path) {
- if (query_appendf(query, " AND file.name GLOB %Q", sindex_search_path) < 0)
+ if (semind_search_path) {
+ if (query_appendf(query, " AND file.name GLOB %Q", semind_search_path) < 0)
goto fail;
}
- if (sindex_search_by_location == EXPLAIN_LOCATION) {
- if (query_appendf(query, " AND file.name == %Q", sindex_search_filename) < 0)
+ if (semind_search_by_location == EXPLAIN_LOCATION) {
+ if (query_appendf(query, " AND file.name == %Q", semind_search_filename) < 0)
goto fail;
- if (sindex_search_line &&
- query_appendf(query, " AND sindex.line == %d", sindex_search_line) < 0)
+ if (semind_search_line &&
+ query_appendf(query, " AND semind.line == %d", semind_search_line) < 0)
goto fail;
- if (sindex_search_column &&
- query_appendf(query, " AND sindex.column == %d", sindex_search_column) < 0)
+ if (semind_search_column &&
+ query_appendf(query, " AND semind.column == %d", semind_search_column) < 0)
goto fail;
- } else if (sindex_search_by_location == USAGE_BY_LOCATION) {
- if (query_appendf(query, " AND sindex.symbol IN (") < 0)
+ } else if (semind_search_by_location == USAGE_BY_LOCATION) {
+ if (query_appendf(query, " AND semind.symbol IN (") < 0)
goto fail;
if (query_appendf(query,
- "SELECT sindex.symbol FROM sindex, file WHERE"
- " sindex.file == file.id AND"
- " file.name == %Q", sindex_search_filename) < 0)
+ "SELECT semind.symbol FROM semind, file WHERE"
+ " semind.file == file.id AND"
+ " file.name == %Q", semind_search_filename) < 0)
goto fail;
- if (sindex_search_line &&
- query_appendf(query, " AND sindex.line == %d", sindex_search_line) < 0)
+ if (semind_search_line &&
+ query_appendf(query, " AND semind.line == %d", semind_search_line) < 0)
goto fail;
- if (sindex_search_column &&
- query_appendf(query, " AND sindex.column == %d", sindex_search_column) < 0)
+ if (semind_search_column &&
+ query_appendf(query, " AND semind.column == %d", semind_search_column) < 0)
goto fail;
if (query_appendf(query, ")") < 0)
goto fail;
}
- if (query_appendf(query, " ORDER BY file.name, sindex.line, sindex.column ASC", sindex_search_path) < 0)
+ if (query_appendf(query, " ORDER BY file.name, semind.line, semind.column ASC", semind_search_path) < 0)
goto fail;
sql = sqlite3_str_value(query);
- if (sindex_verbose > 1)
+ if (semind_verbose > 1)
message("SQL: %s", sql);
- sqlite3_exec(sindex_db, sql, search_query_callback, NULL, &dberr);
+ sqlite3_exec(semind_db, sql, search_query_callback, NULL, &dberr);
if (dberr)
- sindex_error(1, 0, "sql query failed: %s", dberr);
+ semind_error(1, 0, "sql query failed: %s", dberr);
fail:
sql = sqlite3_str_finish(query);
sqlite3_free(sql);
- if (sindex_file_fd) {
- fclose(sindex_file_fd);
- free(sindex_file_name);
+ if (semind_file_fd) {
+ fclose(semind_file_fd);
+ free(semind_file_name);
}
- free(sindex_line);
+ free(semind_line);
}
@@ -1143,25 +1156,25 @@ int main(int argc, char **argv)
progname++;
if (!realpath(".", cwd))
- sindex_error(1, errno, "unable to get current directory");
+ semind_error(1, errno, "unable to get current directory");
n_cwd = strlen(cwd);
parse_cmdline(argc, argv);
for (cmd = commands; cmd->name && strcmp(argv[optind], cmd->name); cmd++);
if (!cmd->name)
- sindex_error(1, 0, "unknown command: %s", argv[optind]);
+ semind_error(1, 0, "unknown command: %s", argv[optind]);
optind++;
- sindex_command = cmd->name;
+ semind_command = cmd->name;
if (cmd->parse_cmdline)
cmd->parse_cmdline(argc, argv);
- open_database(sindex_dbfile, cmd->dbflags);
+ open_database(semind_dbfile, cmd->dbflags);
cmd->handler(argc - optind, argv + optind);
- sqlite3_close(sindex_db);
+ sqlite3_close(semind_db);
return 0;
}
diff --git a/simplify.c b/simplify.c
index 7850bcdc..f6b79685 100644
--- a/simplify.c
+++ b/simplify.c
@@ -754,28 +754,18 @@ static long long check_shift_count(struct instruction *insn, unsigned long long
unsigned int size = insn->size;
long long sval = uval;
+ if (insn->tainted)
+ return -1;
+
if (uval < size)
return uval;
+ insn->tainted = 1;
sval = sign_extend_safe(sval, size);
sval = sign_extend_safe(sval, bits_in_int);
if (sval < 0)
insn->src2 = value_pseudo(sval);
- if (insn->tainted)
- return sval;
-
- if (sval < 0 && Wshift_count_negative)
- warning(insn->pos, "shift count is negative (%lld)", sval);
- if (sval > 0 && Wshift_count_overflow) {
- struct symbol *ctype = insn->type;
- const char *tname;
- if (ctype->type == SYM_NODE)
- ctype = ctype->ctype.base_type;
- tname = show_typename(ctype);
- warning(insn->pos, "shift too big (%llu) for type %s", sval, tname);
- }
- insn->tainted = 1;
- return sval;
+ return -1;
}
static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
diff --git a/sparse.1 b/sparse.1
index 399a63fa..60203d5a 100644
--- a/sparse.1
+++ b/sparse.1
@@ -513,7 +513,7 @@ By default chars are signed.
.BR cgcc (1)
.
.SH HOMEPAGE
-http://www.kernel.org/pub/software/devel/sparse/
+https://sparse.docs.kernel.org
.
.SH MAILING LIST
linux-sparse@vger.kernel.org
diff --git a/symbol.c b/symbol.c
index 2cc9f82d..7f0c8558 100644
--- a/symbol.c
+++ b/symbol.c
@@ -307,6 +307,29 @@ void merge_type(struct symbol *sym, struct symbol *base_type)
merge_type(sym, sym->ctype.base_type);
}
+static bool is_wstring_expr(struct expression *expr)
+{
+ while (expr) {
+ switch (expr->type) {
+ case EXPR_STRING:
+ return 1;
+ case EXPR_INITIALIZER:
+ if (expression_list_size(expr->expr_list) != 1)
+ return 0;
+ expr = first_expression(expr->expr_list);
+ break;
+ case EXPR_PREOP:
+ if (expr->op == '(') {
+ expr = expr->unop;
+ break;
+ }
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
static int count_array_initializer(struct symbol *t, struct expression *expr)
{
int nr = 0;
@@ -321,6 +344,8 @@ static int count_array_initializer(struct symbol *t, struct expression *expr)
*/
if (t->ctype.base_type == &int_type && t->rank == -2)
is_char = 1;
+ else if (t == wchar_ctype && is_wstring_expr(expr))
+ is_char = 1;
switch (expr->type) {
case EXPR_INITIALIZER: {
@@ -776,7 +801,7 @@ struct symbol zero_int;
void init_symbols(void)
{
- int stream = init_stream("builtin", -1, includepath, -1);
+ int stream = init_stream(NULL, "builtin", -1, includepath);
#define __IDENT(n,str,res) \
hash_ident(&n)
diff --git a/symbol.h b/symbol.h
index c2b60ce9..0e15f7bf 100644
--- a/symbol.h
+++ b/symbol.h
@@ -81,7 +81,7 @@ enum keyword {
KW_BUILTIN = 1 << 4,
KW_ASM = 1 << 5,
KW_MODE = 1 << 6,
- // KW UNUSED = 1 << 7,
+ KW_STATIC = 1 << 7,
// KW UNUSED = 1 << 8,
KW_EXACT = 1 << 9,
};
@@ -206,9 +206,10 @@ struct symbol {
union /* backend */ {
struct basic_block *bb_target; /* label */
void *aux; /* Auxiliary info, e.g. backend information */
- struct { /* sparse ctags */
- char kind;
+ struct {
+ char kind; /* used by ctags & dissect */
unsigned char visited:1;
+ unsigned char inspected:1;
};
};
pseudo_t pseudo;
@@ -429,6 +430,13 @@ static inline int is_byte_type(struct symbol *type)
return type->bit_size == bits_in_char && type->type != SYM_BITFIELD;
}
+static inline int is_wchar_type(struct symbol *type)
+{
+ if (type->type == SYM_NODE)
+ type = type->ctype.base_type;
+ return type == wchar_ctype;
+}
+
static inline int is_void_type(struct symbol *type)
{
if (type->type == SYM_NODE)
diff --git a/target-xtensa.c b/target-xtensa.c
index 26bda47f..3620b4a3 100644
--- a/target-xtensa.c
+++ b/target-xtensa.c
@@ -17,11 +17,6 @@ static void predefine_xtensa(const struct target *self)
{
predefine("__XTENSA__", 1, "1");
predefine("__xtensa__", 1, "1");
-
- if (arch_big_endian)
- predefine("__XTENSA_EB__", 1, "1");
- else
- predefine("__XTENSA_EL__", 1, "1");
}
const struct target target_xtensa = {
diff --git a/token.h b/token.h
index 6d2b0b65..bccac0e4 100644
--- a/token.h
+++ b/token.h
@@ -49,10 +49,11 @@ enum constantfile {
extern const char *includepath[];
struct stream {
- int fd, prev;
+ int fd;
const char *name;
const char *path; // input-file path - see set_stream_include_path()
const char **next_path;
+ struct position pos; //position of the #include, if any
/* Use these to check for "already parsed" */
enum constantfile constant;
@@ -214,7 +215,7 @@ static inline struct token *containing_token(struct token **p)
extern struct token eof_token_entry;
#define eof_token(x) ((x) == &eof_token_entry)
-extern int init_stream(const char *, int fd, const char **next_path, int prev_stream);
+extern int init_stream(const struct position *pos, const char *, int fd, const char **next_path);
extern int stream_prev(int stream);
extern const char *stream_name(int stream);
extern struct ident *hash_ident(struct ident *);
@@ -225,7 +226,7 @@ extern const char *show_ident(const struct ident *);
extern const char *show_string(const struct string *string);
extern const char *show_token(const struct token *);
extern const char *quote_token(const struct token *);
-extern struct token * tokenize(const char *, int, int, struct token *, const char **next_path);
+extern struct token * tokenize(const struct position *pos, const char *, int, struct token *, const char **next_path);
extern struct token * tokenize_buffer(void *, unsigned long, struct token **);
extern void show_identifier_stats(void);
diff --git a/tokenize.c b/tokenize.c
index a7b6625b..ea710543 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -66,7 +66,10 @@ int stream_prev(int stream)
{
if (stream < 0 || stream > input_stream_nr)
return -1;
- return input_streams[stream].prev;
+ stream = input_streams[stream].pos.stream;
+ if (stream > input_stream_nr)
+ return -1;
+ return stream;
}
static struct position stream_pos(stream_t *stream)
@@ -307,7 +310,7 @@ int *hash_stream(const char *name)
return input_stream_hashes + hash;
}
-int init_stream(const char *name, int fd, const char **next_path, int prev_stream)
+int init_stream(const struct position *pos, const char *name, int fd, const char **next_path)
{
int stream = input_stream_nr, *hash;
struct stream *current;
@@ -326,7 +329,10 @@ int init_stream(const char *name, int fd, const char **next_path, int prev_strea
current->next_path = next_path;
current->path = NULL;
current->constant = CONSTANT_FILE_MAYBE;
- current->prev = prev_stream;
+ if (pos)
+ current->pos = *pos;
+ else
+ current->pos.stream = -1;
input_stream_nr = stream+1;
hash = hash_stream(name);
current->next_stream = *hash;
@@ -1009,14 +1015,14 @@ struct token * tokenize_buffer(void *buffer, unsigned long size, struct token **
return begin;
}
-struct token * tokenize(const char *name, int fd, int prev_stream, struct token *endtoken, const char **next_path)
+struct token * tokenize(const struct position *pos, const char *name, int fd, struct token *endtoken, const char **next_path)
{
struct token *begin, *end;
stream_t stream;
unsigned char buffer[BUFSIZE];
int idx;
- idx = init_stream(name, fd, next_path, prev_stream);
+ idx = init_stream(pos, name, fd, next_path);
if (idx < 0) {
// info(endtoken->pos, "File %s is const", name);
return endtoken;
diff --git a/validation/abstract-array-declarator-quals.c b/validation/abstract-array-declarator-quals.c
new file mode 100644
index 00000000..e69df902
--- /dev/null
+++ b/validation/abstract-array-declarator-quals.c
@@ -0,0 +1,21 @@
+#define N 2
+
+void ok1(int []);
+void ok2(int [N]);
+void ok3(int [const volatile restrict]);
+void ok4(int [const volatile restrict N]);
+void ok5(int [static N]);
+void ok6(int [static const volatile restrict N]);
+void ok7(int [const volatile restrict static N]);
+
+void ok1(int a[]);
+void ok2(int a[N]);
+void ok3(int a[const volatile restrict]);
+void ok4(int a[const volatile restrict N]);
+void ok5(int a[static N]);
+void ok6(int a[static const volatile restrict N]);
+void ok7(int a[const volatile restrict static N]);
+
+/*
+ * check-name: abstract-array-declarator-quals
+ */
diff --git a/validation/abstract-array-declarator-star.c b/validation/abstract-array-declarator-star.c
new file mode 100644
index 00000000..fc42da3a
--- /dev/null
+++ b/validation/abstract-array-declarator-star.c
@@ -0,0 +1,8 @@
+void ok8(int [*]);
+
+void ok8(int a[*]);
+void ok9(int a[const volatile restrict *]);
+
+/*
+ * check-name: abstract-array-declarator-star
+ */
diff --git a/validation/abstract-array-declarator.c b/validation/abstract-array-declarator.c
new file mode 100644
index 00000000..ca182373
--- /dev/null
+++ b/validation/abstract-array-declarator.c
@@ -0,0 +1,11 @@
+void f77(int a[1, 2]);
+void c99(int a[(1, 2)]);
+
+/*
+ * check-name: abstract-array-declarator
+ *
+ * check-error-start
+abstract-array-declarator.c:1:17: error: Expected ] in abstract_array_declarator
+abstract-array-declarator.c:1:17: error: got ,
+ * check-error-end
+ */
diff --git a/validation/builtin-sync-cas.c b/validation/builtin-sync-cas.c
new file mode 100644
index 00000000..846e21bb
--- /dev/null
+++ b/validation/builtin-sync-cas.c
@@ -0,0 +1,25 @@
+static int *foo(int *ptr)
+{
+ __sync_val_compare_and_swap(ptr, 123, 0L);
+ return __sync_val_compare_and_swap(&ptr, ptr, ptr);
+}
+
+static long bar(long *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, ptr, 1);
+}
+
+static _Bool boz(_Bool *ptr)
+{
+ return __sync_bool_compare_and_swap(ptr, 0, ptr);
+}
+
+/*
+ * check-name: builtin-sync-cas
+ *
+ * check-error-start
+builtin-sync-cas.c:9:49: warning: incorrect type in argument 2 (different base types)
+builtin-sync-cas.c:9:49: expected long
+builtin-sync-cas.c:9:49: got long *ptr
+ * check-error-end
+ */
diff --git a/validation/expand/bad-shift.c b/validation/expand/bad-shift.c
index 22c4341f..b68866c2 100644
--- a/validation/expand/bad-shift.c
+++ b/validation/expand/bad-shift.c
@@ -56,9 +56,9 @@ rneg:
* check-output-end
*
* check-error-start
-expand/bad-shift.c:5:18: warning: shift too big (32) for type int
-expand/bad-shift.c:10:18: warning: shift count is negative (-1)
-expand/bad-shift.c:15:18: warning: shift too big (32) for type int
-expand/bad-shift.c:20:18: warning: shift count is negative (-1)
+expand/bad-shift.c:5:21: warning: shift too big (32) for type int
+expand/bad-shift.c:10:21: warning: shift count is negative (-1)
+expand/bad-shift.c:15:21: warning: shift too big (32) for type int
+expand/bad-shift.c:20:21: warning: shift count is negative (-1)
* check-error-end
*/
diff --git a/validation/init-wstring.c b/validation/init-wstring.c
new file mode 100644
index 00000000..d9ce3b3c
--- /dev/null
+++ b/validation/init-wstring.c
@@ -0,0 +1,40 @@
+static const __WCHAR_TYPE__ ok0[] = L"abc";
+_Static_assert(sizeof(ok0) == 4 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok1[] = (L"abc");
+_Static_assert(sizeof(ok1) == 4 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok2[] = { L"abc" };
+_Static_assert(sizeof(ok2) == 4 * sizeof(__WCHAR_TYPE__));
+
+static const __WCHAR_TYPE__ ok3[4] = L"abc";
+_Static_assert(sizeof(ok3) == 4 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok4[4] = (L"abc");
+_Static_assert(sizeof(ok4) == 4 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok5[4] = { (L"abc") };
+_Static_assert(sizeof(ok5) == 4 * sizeof(__WCHAR_TYPE__));
+
+static const __WCHAR_TYPE__ ok6[7] = L"abc";
+_Static_assert(sizeof(ok6) == 7 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok7[7] = (L"abc");
+_Static_assert(sizeof(ok7) == 7 * sizeof(__WCHAR_TYPE__));
+static const __WCHAR_TYPE__ ok8[7] = { (L"abc") };
+_Static_assert(sizeof(ok8) == 7 * sizeof(__WCHAR_TYPE__));
+
+static const __WCHAR_TYPE__ *ptr[] = { L"abc" };
+_Static_assert(sizeof(ptr) == sizeof(void *));
+
+static struct s {
+ const __WCHAR_TYPE__ str[4];
+} str = { L"xyz" };
+
+static const __WCHAR_TYPE__ ko3[3] = L"abc";
+static const __WCHAR_TYPE__ ko2[2] = L"abc";
+
+/*
+ * check-name: init-wstring
+ * check-command: sparse -Winit-cstring $file
+ *
+ * check-error-start
+init-wstring.c:29:38: warning: too long initializer-string for array of char(no space for nul char)
+init-wstring.c:30:38: warning: too long initializer-string for array of char
+ * check-error-end
+ */
diff --git a/validation/init_cstring.c b/validation/init_cstring.c
index 00eca20a..bac814e4 100644
--- a/validation/init_cstring.c
+++ b/validation/init_cstring.c
@@ -1,11 +1,13 @@
static struct alpha {
char a[2];
} x = { .a = "ab" };
+static const char str[2] = "abc";
/*
* check-name: -Winit-cstring option
*
* check-command: sparse -Winit-cstring $file
* check-error-start
init_cstring.c:3:14: warning: too long initializer-string for array of char(no space for nul char)
+init_cstring.c:4:28: warning: too long initializer-string for array of char
* check-error-end
*/
diff --git a/validation/inline-generic.c b/validation/inline-generic.c
new file mode 100644
index 00000000..1f05c079
--- /dev/null
+++ b/validation/inline-generic.c
@@ -0,0 +1,10 @@
+extern int a, b;
+inline int c(void) { return a++; }
+inline int e(int d) { return 0; }
+inline unsigned f(void) { return e(_Generic(b, int: c())); }
+static int g(void) { return f(); }
+static int h(void) { return f(); }
+
+/*
+ * check-name: inline-generic
+ */
diff --git a/validation/linear/bug-assign-op0.c b/validation/linear/bug-assign-op0.c
index 0cabc622..b351bb51 100644
--- a/validation/linear/bug-assign-op0.c
+++ b/validation/linear/bug-assign-op0.c
@@ -46,7 +46,6 @@ unsigned int sldivu(unsigned int u, long s)
/*
* check-name: bug-assign-op0
* check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
*
* check-output-start
asr:
diff --git a/validation/linear/shift-assign1.c b/validation/linear/shift-assign1.c
new file mode 100644
index 00000000..4c96fc28
--- /dev/null
+++ b/validation/linear/shift-assign1.c
@@ -0,0 +1,319 @@
+typedef __INT16_TYPE__ s16;
+typedef __INT32_TYPE__ s32;
+typedef __INT64_TYPE__ s64;
+typedef __UINT16_TYPE__ u16;
+typedef __UINT32_TYPE__ u32;
+typedef __UINT64_TYPE__ u64;
+
+s16 s16s16(s16 a, s16 b) { a >>= b; return a; }
+s16 s16s32(s16 a, s32 b) { a >>= b; return a; }
+s16 s16s64(s16 a, s64 b) { a >>= b; return a; }
+s16 s16u16(s16 a, u16 b) { a >>= b; return a; }
+s16 s16u32(s16 a, u32 b) { a >>= b; return a; }
+s16 s16u64(s16 a, u64 b) { a >>= b; return a; }
+s32 s32s16(s32 a, s16 b) { a >>= b; return a; }
+s32 s32s32(s32 a, s32 b) { a >>= b; return a; }
+s32 s32s64(s32 a, s64 b) { a >>= b; return a; }
+s32 s32u16(s32 a, u16 b) { a >>= b; return a; }
+s32 s32u32(s32 a, u32 b) { a >>= b; return a; }
+s32 s32u64(s32 a, u64 b) { a >>= b; return a; }
+s64 s64s16(s64 a, s16 b);
+s64 s64s32(s64 a, s32 b);
+s64 s64s64(s64 a, s64 b) { a >>= b; return a; }
+s64 s64u16(s64 a, u16 b) { a >>= b; return a; }
+s64 s64u32(s64 a, u32 b) { a >>= b; return a; }
+s64 s64u64(s64 a, u64 b) { a >>= b; return a; }
+u16 u16s16(u16 a, s16 b) { a >>= b; return a; }
+u16 u16s32(u16 a, s32 b) { a >>= b; return a; }
+u16 u16s64(u16 a, s64 b) { a >>= b; return a; }
+u16 u16u16(u16 a, u16 b) { a >>= b; return a; }
+u16 u16u32(u16 a, u32 b) { a >>= b; return a; }
+u16 u16u64(u16 a, u64 b) { a >>= b; return a; }
+u32 u32s16(u32 a, s16 b) { a >>= b; return a; }
+u32 u32s32(u32 a, s32 b) { a >>= b; return a; }
+u32 u32s64(u32 a, s64 b) { a >>= b; return a; }
+u32 u32u16(u32 a, u16 b) { a >>= b; return a; }
+u32 u32u32(u32 a, u32 b) { a >>= b; return a; }
+u32 u32u64(u32 a, u64 b) { a >>= b; return a; }
+u64 u64s16(u64 a, s16 b);
+u64 u64s32(u64 a, s32 b);
+u64 u64s64(u64 a, s64 b) { a >>= b; return a; }
+u64 u64u16(u64 a, u16 b) { a >>= b; return a; }
+u64 u64u32(u64 a, u32 b) { a >>= b; return a; }
+u64 u64u64(u64 a, u64 b) { a >>= b; return a; }
+
+/*
+ * check-name: shift-assign1
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+s16s16:
+.L0:
+ <entry-point>
+ sext.32 %r2 <- (16) %arg2
+ sext.32 %r4 <- (16) %arg1
+ asr.32 %r5 <- %r4, %r2
+ trunc.16 %r6 <- (32) %r5
+ ret.16 %r6
+
+
+s16s32:
+.L2:
+ <entry-point>
+ sext.32 %r11 <- (16) %arg1
+ asr.32 %r12 <- %r11, %arg2
+ trunc.16 %r13 <- (32) %r12
+ ret.16 %r13
+
+
+s16s64:
+.L4:
+ <entry-point>
+ trunc.32 %r17 <- (64) %arg2
+ sext.32 %r19 <- (16) %arg1
+ asr.32 %r20 <- %r19, %r17
+ trunc.16 %r21 <- (32) %r20
+ ret.16 %r21
+
+
+s16u16:
+.L6:
+ <entry-point>
+ zext.32 %r25 <- (16) %arg2
+ sext.32 %r27 <- (16) %arg1
+ asr.32 %r28 <- %r27, %r25
+ trunc.16 %r29 <- (32) %r28
+ ret.16 %r29
+
+
+s16u32:
+.L8:
+ <entry-point>
+ sext.32 %r34 <- (16) %arg1
+ asr.32 %r35 <- %r34, %arg2
+ trunc.16 %r36 <- (32) %r35
+ ret.16 %r36
+
+
+s16u64:
+.L10:
+ <entry-point>
+ trunc.32 %r40 <- (64) %arg2
+ sext.32 %r42 <- (16) %arg1
+ asr.32 %r43 <- %r42, %r40
+ trunc.16 %r44 <- (32) %r43
+ ret.16 %r44
+
+
+s32s16:
+.L12:
+ <entry-point>
+ sext.32 %r48 <- (16) %arg2
+ asr.32 %r50 <- %arg1, %r48
+ ret.32 %r50
+
+
+s32s32:
+.L14:
+ <entry-point>
+ asr.32 %r55 <- %arg1, %arg2
+ ret.32 %r55
+
+
+s32s64:
+.L16:
+ <entry-point>
+ trunc.32 %r59 <- (64) %arg2
+ asr.32 %r61 <- %arg1, %r59
+ ret.32 %r61
+
+
+s32u16:
+.L18:
+ <entry-point>
+ zext.32 %r65 <- (16) %arg2
+ asr.32 %r67 <- %arg1, %r65
+ ret.32 %r67
+
+
+s32u32:
+.L20:
+ <entry-point>
+ asr.32 %r72 <- %arg1, %arg2
+ ret.32 %r72
+
+
+s32u64:
+.L22:
+ <entry-point>
+ trunc.32 %r76 <- (64) %arg2
+ asr.32 %r78 <- %arg1, %r76
+ ret.32 %r78
+
+
+s64s64:
+.L24:
+ <entry-point>
+ asr.64 %r83 <- %arg1, %arg2
+ ret.64 %r83
+
+
+s64u16:
+.L26:
+ <entry-point>
+ zext.64 %r88 <- (16) %arg2
+ asr.64 %r90 <- %arg1, %r88
+ ret.64 %r90
+
+
+s64u32:
+.L28:
+ <entry-point>
+ zext.64 %r94 <- (32) %arg2
+ asr.64 %r96 <- %arg1, %r94
+ ret.64 %r96
+
+
+s64u64:
+.L30:
+ <entry-point>
+ asr.64 %r101 <- %arg1, %arg2
+ ret.64 %r101
+
+
+u16s16:
+.L32:
+ <entry-point>
+ sext.32 %r105 <- (16) %arg2
+ zext.32 %r107 <- (16) %arg1
+ asr.32 %r108 <- %r107, %r105
+ trunc.16 %r109 <- (32) %r108
+ ret.16 %r109
+
+
+u16s32:
+.L34:
+ <entry-point>
+ zext.32 %r114 <- (16) %arg1
+ asr.32 %r115 <- %r114, %arg2
+ trunc.16 %r116 <- (32) %r115
+ ret.16 %r116
+
+
+u16s64:
+.L36:
+ <entry-point>
+ trunc.32 %r120 <- (64) %arg2
+ zext.32 %r122 <- (16) %arg1
+ asr.32 %r123 <- %r122, %r120
+ trunc.16 %r124 <- (32) %r123
+ ret.16 %r124
+
+
+u16u16:
+.L38:
+ <entry-point>
+ zext.32 %r128 <- (16) %arg2
+ zext.32 %r130 <- (16) %arg1
+ asr.32 %r131 <- %r130, %r128
+ trunc.16 %r132 <- (32) %r131
+ ret.16 %r132
+
+
+u16u32:
+.L40:
+ <entry-point>
+ zext.32 %r137 <- (16) %arg1
+ asr.32 %r138 <- %r137, %arg2
+ trunc.16 %r139 <- (32) %r138
+ ret.16 %r139
+
+
+u16u64:
+.L42:
+ <entry-point>
+ trunc.32 %r143 <- (64) %arg2
+ zext.32 %r145 <- (16) %arg1
+ asr.32 %r146 <- %r145, %r143
+ trunc.16 %r147 <- (32) %r146
+ ret.16 %r147
+
+
+u32s16:
+.L44:
+ <entry-point>
+ sext.32 %r151 <- (16) %arg2
+ lsr.32 %r153 <- %arg1, %r151
+ ret.32 %r153
+
+
+u32s32:
+.L46:
+ <entry-point>
+ lsr.32 %r158 <- %arg1, %arg2
+ ret.32 %r158
+
+
+u32s64:
+.L48:
+ <entry-point>
+ trunc.32 %r162 <- (64) %arg2
+ lsr.32 %r164 <- %arg1, %r162
+ ret.32 %r164
+
+
+u32u16:
+.L50:
+ <entry-point>
+ zext.32 %r168 <- (16) %arg2
+ lsr.32 %r170 <- %arg1, %r168
+ ret.32 %r170
+
+
+u32u32:
+.L52:
+ <entry-point>
+ lsr.32 %r175 <- %arg1, %arg2
+ ret.32 %r175
+
+
+u32u64:
+.L54:
+ <entry-point>
+ trunc.32 %r179 <- (64) %arg2
+ lsr.32 %r181 <- %arg1, %r179
+ ret.32 %r181
+
+
+u64s64:
+.L56:
+ <entry-point>
+ lsr.64 %r186 <- %arg1, %arg2
+ ret.64 %r186
+
+
+u64u16:
+.L58:
+ <entry-point>
+ zext.64 %r191 <- (16) %arg2
+ lsr.64 %r193 <- %arg1, %r191
+ ret.64 %r193
+
+
+u64u32:
+.L60:
+ <entry-point>
+ zext.64 %r197 <- (32) %arg2
+ lsr.64 %r199 <- %arg1, %r197
+ ret.64 %r199
+
+
+u64u64:
+.L62:
+ <entry-point>
+ lsr.64 %r204 <- %arg1, %arg2
+ ret.64 %r204
+
+
+ * check-output-end
+ */
diff --git a/validation/linear/shift-assign2.c b/validation/linear/shift-assign2.c
new file mode 100644
index 00000000..9990ac38
--- /dev/null
+++ b/validation/linear/shift-assign2.c
@@ -0,0 +1,53 @@
+typedef __INT16_TYPE__ s16;
+typedef __INT32_TYPE__ s32;
+typedef __INT64_TYPE__ s64;
+typedef __UINT16_TYPE__ u16;
+typedef __UINT32_TYPE__ u32;
+typedef __UINT64_TYPE__ u64;
+
+s64 s64s16(s64 a, s16 b) { a >>= b; return a; }
+s64 s64s32(s64 a, s32 b) { a >>= b; return a; }
+u64 u64s16(u64 a, s16 b) { a >>= b; return a; }
+u64 u64s32(u64 a, s32 b) { a >>= b; return a; }
+
+/*
+ * check-name: shift-assign2
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+s64s16:
+.L0:
+ <entry-point>
+ sext.32 %r2 <- (16) %arg2
+ zext.64 %r3 <- (32) %r2
+ asr.64 %r5 <- %arg1, %r3
+ ret.64 %r5
+
+
+s64s32:
+.L2:
+ <entry-point>
+ zext.64 %r9 <- (32) %arg2
+ asr.64 %r11 <- %arg1, %r9
+ ret.64 %r11
+
+
+u64s16:
+.L4:
+ <entry-point>
+ sext.32 %r15 <- (16) %arg2
+ zext.64 %r16 <- (32) %r15
+ lsr.64 %r18 <- %arg1, %r16
+ ret.64 %r18
+
+
+u64s32:
+.L6:
+ <entry-point>
+ zext.64 %r22 <- (32) %arg2
+ lsr.64 %r24 <- %arg1, %r22
+ ret.64 %r24
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c
index 84bcd2ce..e7bf22fe 100644
--- a/validation/optim/shift-big.c
+++ b/validation/optim/shift-big.c
@@ -50,13 +50,15 @@ lsr31:
lsr32:
.L8:
<entry-point>
- ret.32 $0
+ lsr.32 %r14 <- %arg1, $32
+ ret.32 %r14
lsr33:
.L10:
<entry-point>
- ret.32 $0
+ lsr.32 %r17 <- %arg1, $33
+ ret.32 %r17
shl31:
@@ -69,13 +71,15 @@ shl31:
shl32:
.L14:
<entry-point>
- ret.32 $0
+ shl.32 %r23 <- %arg1, $32
+ ret.32 %r23
shl33:
.L16:
<entry-point>
- ret.32 $0
+ shl.32 %r26 <- %arg1, $33
+ ret.32 %r26
* check-output-end
diff --git a/validation/preprocessor/bad-cmdline-include.c b/validation/preprocessor/bad-cmdline-include.c
new file mode 100644
index 00000000..e4ee03f4
--- /dev/null
+++ b/validation/preprocessor/bad-cmdline-include.c
@@ -0,0 +1,11 @@
+#error some random error
+
+/*
+ * check-name: bad-cmdline-include
+ * check-command: sparse -include $file
+ *
+ * check-error-start
+command-line: note: in included file (through builtin):
+preprocessor/bad-cmdline-include.c:1:2: error: some random error
+ * check-error-end
+ */
diff --git a/validation/shift-negative.c b/validation/shift-negative.c
index fff5cf12..6df02b18 100644
--- a/validation/shift-negative.c
+++ b/validation/shift-negative.c
@@ -9,8 +9,8 @@ unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); }
* check-command: sparse -Wno-decl $file
*
* check-error-start
-shift-negative.c:1:45: warning: shift count is negative (-1)
-shift-negative.c:2:45: warning: shift count is negative (-1)
+shift-negative.c:1:48: warning: shift count is negative (-1)
+shift-negative.c:2:48: warning: shift count is negative (-1)
shift-negative.c:4:59: warning: shift count is negative (-1)
shift-negative.c:5:59: warning: shift count is negative (-1)
* check-error-end
diff --git a/validation/shift-undef-long.c b/validation/shift-undef-long.c
index 32626743..985fe4c4 100644
--- a/validation/shift-undef-long.c
+++ b/validation/shift-undef-long.c
@@ -13,9 +13,8 @@ static unsigned very_big_shift(unsigned int a)
* check-command: sparse -m64 $file
*
* check-error-start
-shift-undef-long.c:4:16: warning: shift too big (4294967295) for type unsigned int
-shift-undef-long.c:5:16: warning: shift too big (4294967296) for type unsigned int
-shift-undef-long.c:6:16: warning: shift too big (4294967296) for type unsigned int
-shift-undef-long.c:7:16: warning: shift count is negative (-4294967296)
+shift-undef-long.c:4:25: warning: shift count is negative (-1)
+shift-undef-long.c:5:47: warning: shift too big (4294967296) for type unsigned int
+shift-undef-long.c:7:20: warning: shift count is negative (-4294967296)
* check-error-end
*/
diff --git a/validation/shift-undef.c b/validation/shift-undef.c
index 4e94fa23..0c7541e9 100644
--- a/validation/shift-undef.c
+++ b/validation/shift-undef.c
@@ -112,51 +112,27 @@ void hw_write(u32 val)
* check-command: sparse -Wno-decl $file
*
* check-error-start
-shift-undef.c:3:15: warning: shift too big (100) for type int
-shift-undef.c:4:15: warning: shift too big (101) for type unsigned int
-shift-undef.c:5:15: warning: shift too big (102) for type unsigned int
-shift-undef.c:6:15: warning: shift count is negative (-1)
-shift-undef.c:7:15: warning: shift count is negative (-2)
-shift-undef.c:8:15: warning: shift count is negative (-3)
-shift-undef.c:9:25: warning: shift too big (103) for type int
-shift-undef.c:10:25: warning: shift too big (104) for type unsigned int
-shift-undef.c:11:25: warning: shift too big (105) for type unsigned int
-shift-undef.c:12:25: warning: shift count is negative (-4)
-shift-undef.c:13:25: warning: shift count is negative (-5)
-shift-undef.c:14:25: warning: shift count is negative (-6)
-shift-undef.c:15:30: warning: shift too big (106) for type int
-shift-undef.c:16:30: warning: shift too big (107) for type unsigned int
-shift-undef.c:17:30: warning: shift too big (108) for type unsigned int
-shift-undef.c:18:30: warning: shift count is negative (-7)
-shift-undef.c:19:30: warning: shift count is negative (-8)
-shift-undef.c:20:30: warning: shift count is negative (-9)
+shift-undef.c:3:18: warning: shift too big (100) for type int
+shift-undef.c:4:18: warning: shift too big (101) for type unsigned int
+shift-undef.c:5:18: warning: shift too big (102) for type unsigned int
+shift-undef.c:6:19: warning: shift count is negative (-1)
+shift-undef.c:7:19: warning: shift count is negative (-2)
+shift-undef.c:8:19: warning: shift count is negative (-3)
shift-undef.c:21:29: warning: shift too big (109) for type int
shift-undef.c:22:29: warning: shift too big (110) for type unsigned int
shift-undef.c:23:29: warning: shift too big (111) for type unsigned int
shift-undef.c:24:29: warning: shift count is negative (-10)
shift-undef.c:25:29: warning: shift count is negative (-11)
shift-undef.c:26:29: warning: shift count is negative (-12)
-shift-undef.c:32:11: warning: shift too big (100) for type int
-shift-undef.c:33:11: warning: shift too big (101) for type unsigned int
-shift-undef.c:34:11: warning: shift too big (102) for type unsigned int
-shift-undef.c:35:11: warning: shift count is negative (-1)
-shift-undef.c:36:11: warning: shift count is negative (-2)
-shift-undef.c:37:11: warning: shift count is negative (-3)
-shift-undef.c:38:25: warning: shift too big (103) for type int
-shift-undef.c:39:25: warning: shift too big (104) for type unsigned int
-shift-undef.c:40:25: warning: shift too big (105) for type unsigned int
-shift-undef.c:41:25: warning: shift count is negative (-4)
-shift-undef.c:42:25: warning: shift count is negative (-5)
-shift-undef.c:43:25: warning: shift count is negative (-6)
-shift-undef.c:44:30: warning: shift too big (106) for type int
-shift-undef.c:45:30: warning: shift too big (107) for type unsigned int
-shift-undef.c:46:30: warning: shift too big (108) for type unsigned int
-shift-undef.c:47:30: warning: shift count is negative (-7)
-shift-undef.c:48:30: warning: shift count is negative (-8)
-shift-undef.c:49:30: warning: shift count is negative (-9)
+shift-undef.c:32:15: warning: shift too big (100) for type int
+shift-undef.c:33:15: warning: shift too big (101) for type unsigned int
+shift-undef.c:34:15: warning: shift too big (102) for type unsigned int
+shift-undef.c:35:16: warning: shift count is negative (-1)
+shift-undef.c:36:16: warning: shift count is negative (-2)
+shift-undef.c:37:16: warning: shift count is negative (-3)
shift-undef.c:50:26: warning: shift too big (109) for type int
-shift-undef.c:51:26: warning: shift too big (110) for type int
-shift-undef.c:52:26: warning: shift too big (111) for type int
+shift-undef.c:51:26: warning: shift too big (110) for type unsigned int
+shift-undef.c:52:26: warning: shift too big (111) for type unsigned int
shift-undef.c:53:26: warning: shift count is negative (-10)
shift-undef.c:54:26: warning: shift count is negative (-11)
shift-undef.c:55:26: warning: shift count is negative (-12)