aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--evaluate.c36
-rw-r--r--expand.c2
-rw-r--r--expression.c12
-rw-r--r--linearize.c2
-rw-r--r--parse.c73
-rw-r--r--parse.h4
-rw-r--r--scope.c42
-rw-r--r--scope.h10
-rw-r--r--symbol.c13
-rw-r--r--symbol.h7
-rw-r--r--validation/__func__-scope.c8
-rw-r--r--validation/asm-goto-labels.c (renamed from validation/asm-goto-lables.c)0
-rw-r--r--validation/label-asm.c1
-rw-r--r--validation/label-attr.c2
-rw-r--r--validation/label-scope-cgoto.c82
-rw-r--r--validation/label-scope.c5
-rw-r--r--validation/label-scope1.c42
-rw-r--r--validation/label-scope2.c31
-rw-r--r--validation/label-stmt-expr0.c38
-rw-r--r--validation/label-stmt-expr1.c28
-rw-r--r--validation/label-stmt-expr2.c46
-rw-r--r--validation/label-unused.c29
-rw-r--r--validation/linear/goto-invalid.c18
-rw-r--r--validation/linear/goto-stmt-expr-conditional.c27
-rw-r--r--validation/linear/goto-stmt-expr-short-circuit.c31
-rw-r--r--validation/linear/label-scope-cgoto.c10
-rw-r--r--validation/linear/label-stmt-dropped.c (renamed from validation/discarded-label-statement.c)4
-rw-r--r--validation/linear/label-stmt-expr0.c (renamed from validation/label-expr.c)4
-rw-r--r--validation/linear/label-unreachable.c (renamed from validation/linear/unreachable-label0.c)3
-rw-r--r--validation/nested-functions.c43
-rw-r--r--validation/typeof-safe.c27
31 files changed, 617 insertions, 63 deletions
diff --git a/evaluate.c b/evaluate.c
index b7bb1f52..63d75d90 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -3257,6 +3257,21 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
return size_t_ctype;
}
+static void check_label_declaration(struct position pos, struct symbol *label)
+{
+ switch (label->namespace) {
+ case NS_LABEL:
+ if (label->stmt)
+ break;
+ sparse_error(pos, "label '%s' was not declared", show_ident(label->ident));
+ /* fallthrough */
+ case NS_NONE:
+ current_fn->bogus_linear = 1;
+ default:
+ break;
+ }
+}
+
struct symbol *evaluate_expression(struct expression *expr)
{
if (!expr)
@@ -3329,6 +3344,7 @@ struct symbol *evaluate_expression(struct expression *expr)
case EXPR_LABEL:
expr->ctype = &ptr_ctype;
+ check_label_declaration(expr->pos, expr->label_symbol);
return &ptr_ctype;
case EXPR_TYPE:
@@ -3422,7 +3438,7 @@ static struct symbol *evaluate_symbol(struct symbol *sym)
if (sym->definition && sym->definition != sym)
return evaluate_symbol(sym->definition);
- current_fn = base_type;
+ current_fn = sym;
examine_fn_arguments(base_type);
if (!base_type->stmt && base_type->inline_stmt)
@@ -3450,13 +3466,14 @@ void evaluate_symbol_list(struct symbol_list *list)
static struct symbol *evaluate_return_expression(struct statement *stmt)
{
struct expression *expr = stmt->expression;
- struct symbol *fntype;
+ struct symbol *fntype, *rettype;
evaluate_expression(expr);
fntype = current_fn->ctype.base_type;
- if (!fntype || fntype == &void_ctype) {
+ rettype = fntype->ctype.base_type;
+ if (!rettype || rettype == &void_ctype) {
if (expr && expr->ctype != &void_ctype)
- expression_error(expr, "return expression in %s function", fntype?"void":"typeless");
+ expression_error(expr, "return expression in %s function", rettype?"void":"typeless");
if (expr && Wreturn_void)
warning(stmt->pos, "returning void-valued expression");
return NULL;
@@ -3468,7 +3485,7 @@ static struct symbol *evaluate_return_expression(struct statement *stmt)
}
if (!expr->ctype)
return NULL;
- compatible_assignment_types(expr, fntype, &stmt->expression, "return expression");
+ compatible_assignment_types(expr, rettype, &stmt->expression, "return expression");
return NULL;
}
@@ -3741,10 +3758,13 @@ static void evaluate_goto_statement(struct statement *stmt)
{
struct symbol *label = stmt->goto_label;
- if (label && !label->stmt && label->ident && !lookup_keyword(label->ident, NS_KEYWORD))
- sparse_error(stmt->pos, "label '%s' was not declared", show_ident(label->ident));
+ if (!label) {
+ // no label associated, may be a computed goto
+ evaluate_expression(stmt->goto_expression);
+ return;
+ }
- evaluate_expression(stmt->goto_expression);
+ check_label_declaration(stmt->pos, label);
}
struct symbol *evaluate_statement(struct statement *stmt)
diff --git a/expand.c b/expand.c
index e7559878..ab296c73 100644
--- a/expand.c
+++ b/expand.c
@@ -918,7 +918,7 @@ static int expand_symbol_call(struct expression *expr, int cost)
struct symbol *fn = def->ctype.base_type;
struct symbol *curr = current_fn;
- current_fn = fn;
+ current_fn = def;
evaluate_statement(expr->statement);
current_fn = curr;
diff --git a/expression.c b/expression.c
index 5b9bddfe..99a6d756 100644
--- a/expression.c
+++ b/expression.c
@@ -71,9 +71,9 @@ struct token *parens_expression(struct token *token, struct expression **expr, c
struct statement *stmt = alloc_statement(token->pos, STMT_COMPOUND);
*expr = e;
e->statement = stmt;
- start_symbol_scope();
+ start_label_scope();
token = compound_statement(token->next, stmt);
- end_symbol_scope();
+ end_label_scope();
token = expect(token, '}', "at end of statement expression");
} else
token = parse_expression(token, expr);
@@ -124,9 +124,8 @@ static struct symbol *handle_func(struct token *token)
decl->ctype.modifiers = MOD_STATIC;
decl->endpos = token->pos;
- /* function-scope, but in NS_SYMBOL */
- bind_symbol(decl, ident, NS_LABEL);
- decl->namespace = NS_SYMBOL;
+ /* NS_SYMBOL but in function-scope */
+ bind_symbol_with_scope(decl, ident, NS_SYMBOL, function_scope);
len = current_fn->ident->len;
string = __alloc_string(len + 1);
@@ -687,11 +686,12 @@ static struct token *unary_expression(struct token *token, struct expression **t
if (match_op(token, SPECIAL_LOGICAL_AND) &&
token_type(token->next) == TOKEN_IDENT) {
struct expression *label = alloc_expression(token->pos, EXPR_LABEL);
- struct symbol *sym = label_symbol(token->next);
+ struct symbol *sym = label_symbol(token->next, 1);
if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) {
sym->ctype.modifiers |= MOD_ADDRESSABLE;
add_symbol(&function_computed_target_list, sym);
}
+ check_label_usage(sym, token->pos);
label->flags = CEF_ADDR;
label->label_symbol = sym;
*tree = label;
diff --git a/linearize.c b/linearize.c
index b040d345..49274681 100644
--- a/linearize.c
+++ b/linearize.c
@@ -2480,7 +2480,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
pseudo_t result;
int i;
- if (!stmt)
+ if (!stmt || sym->bogus_linear)
return NULL;
ep = alloc_entrypoint();
diff --git a/parse.c b/parse.c
index c1a72ae2..1ec95228 100644
--- a/parse.c
+++ b/parse.c
@@ -721,12 +721,14 @@ static struct symbol * alloc_indirect_symbol(struct position pos, struct ctype *
* it also ends up using function scope instead of the
* regular symbol scope.
*/
-struct symbol *label_symbol(struct token *token)
+struct symbol *label_symbol(struct token *token, int used)
{
struct symbol *sym = lookup_symbol(token->ident, NS_LABEL);
if (!sym) {
sym = alloc_symbol(token->pos, SYM_LABEL);
bind_symbol(sym, token->ident, NS_LABEL);
+ if (used)
+ sym->used = 1;
fn_local_symbol(sym);
}
return sym;
@@ -2127,7 +2129,7 @@ static struct token *parse_asm_labels(struct token *token, struct statement *stm
token = token->next; /* skip ':' and ',' */
if (token_type(token) != TOKEN_IDENT)
return token;
- label = label_symbol(token);
+ label = label_symbol(token, 1);
add_symbol(labels, label);
token = token->next;
} while (match_op(token, ','));
@@ -2218,7 +2220,7 @@ static void start_iterator(struct statement *stmt)
{
struct symbol *cont, *brk;
- start_symbol_scope();
+ start_block_scope();
cont = alloc_symbol(stmt->pos, SYM_NODE);
bind_symbol(cont, &continue_ident, NS_ITERATOR);
brk = alloc_symbol(stmt->pos, SYM_NODE);
@@ -2233,7 +2235,7 @@ static void start_iterator(struct statement *stmt)
static void end_iterator(struct statement *stmt)
{
- end_symbol_scope();
+ end_block_scope();
}
static struct statement *start_function(struct symbol *sym)
@@ -2278,7 +2280,7 @@ static void start_switch(struct statement *stmt)
{
struct symbol *brk, *switch_case;
- start_symbol_scope();
+ start_block_scope();
brk = alloc_symbol(stmt->pos, SYM_NODE);
bind_symbol(brk, &break_ident, NS_ITERATOR);
@@ -2298,7 +2300,7 @@ static void end_switch(struct statement *stmt)
{
if (!stmt->switch_case->symbol_list)
warning(stmt->pos, "switch with no cases");
- end_symbol_scope();
+ end_block_scope();
}
static void add_case_statement(struct statement *stmt)
@@ -2468,6 +2470,27 @@ static struct token *parse_switch_statement(struct token *token, struct statemen
return token;
}
+static void warn_label_usage(struct position def, struct position use, struct ident *ident)
+{
+ const char *id = show_ident(ident);
+ sparse_error(use, "label '%s' used outside statement expression", id);
+ info(def, " label '%s' defined here", id);
+ current_fn->bogus_linear = 1;
+}
+
+void check_label_usage(struct symbol *label, struct position use_pos)
+{
+ struct statement *def = label->stmt;
+
+ if (def) {
+ if (!is_in_scope(def->label_scope, label_scope))
+ warn_label_usage(def->pos, use_pos, label->ident);
+ } else if (!label->label_scope) {
+ label->label_scope = label_scope;
+ label->label_pos = use_pos;
+ }
+}
+
static struct token *parse_goto_statement(struct token *token, struct statement *stmt)
{
stmt->type = STMT_GOTO;
@@ -2476,7 +2499,9 @@ static struct token *parse_goto_statement(struct token *token, struct statement
token = parse_expression(token->next, &stmt->goto_expression);
add_statement(&function_computed_goto_list, stmt);
} else if (token_type(token) == TOKEN_IDENT) {
- stmt->goto_label = label_symbol(token);
+ struct symbol *label = label_symbol(token, 1);
+ stmt->goto_label = label;
+ check_label_usage(label, stmt->pos);
token = token->next;
} else {
sparse_error(token->pos, "Expected identifier or goto expression");
@@ -2517,6 +2542,15 @@ static struct token *parse_range_statement(struct token *token, struct statement
return expect(token, ';', "after range statement");
}
+static struct token *handle_label_attributes(struct token *token, struct symbol *label)
+{
+ struct decl_state ctx = { };
+
+ token = handle_attributes(token, &ctx, KW_ATTRIBUTE);
+ label->label_modifiers = ctx.ctype.modifiers;
+ return token;
+}
+
static struct token *statement(struct token *token, struct statement **tree)
{
struct statement *stmt = alloc_statement(token->pos, STMT_NONE);
@@ -2528,8 +2562,8 @@ static struct token *statement(struct token *token, struct statement **tree)
return s->op->statement(token, stmt);
if (match_op(token->next, ':')) {
- struct symbol *s = label_symbol(token);
- token = skip_attributes(token->next->next);
+ struct symbol *s = label_symbol(token, 0);
+ token = handle_label_attributes(token->next->next, s);
if (s->stmt) {
sparse_error(stmt->pos, "label '%s' redefined", show_ident(s->ident));
// skip the label to avoid multiple definitions
@@ -2537,17 +2571,18 @@ static struct token *statement(struct token *token, struct statement **tree)
}
stmt->type = STMT_LABEL;
stmt->label_identifier = s;
+ stmt->label_scope = label_scope;
+ if (s->label_scope) {
+ if (!is_in_scope(label_scope, s->label_scope))
+ warn_label_usage(stmt->pos, s->label_pos, s->ident);
+ }
s->stmt = stmt;
return statement(token, &stmt->label_statement);
}
}
if (match_op(token, '{')) {
- stmt->type = STMT_COMPOUND;
- start_symbol_scope();
token = compound_statement(token->next, stmt);
- end_symbol_scope();
-
return expect(token, '}', "at end of compound statement");
}
@@ -2561,8 +2596,7 @@ static struct token *label_statement(struct token *token)
while (token_type(token) == TOKEN_IDENT) {
struct symbol *sym = alloc_symbol(token->pos, SYM_LABEL);
/* it's block-scope, but we want label namespace */
- bind_symbol(sym, token->ident, NS_SYMBOL);
- sym->namespace = NS_LABEL;
+ bind_symbol_with_scope(sym, token->ident, NS_LABEL, block_scope);
fn_local_symbol(sym);
token = token->next;
if (!match_op(token, ','))
@@ -2654,7 +2688,10 @@ static struct token *parameter_type_list(struct token *token, struct symbol *fn)
struct token *compound_statement(struct token *token, struct statement *stmt)
{
+ stmt->type = STMT_COMPOUND;
+ start_block_scope();
token = statement_list(token, &stmt->stmts);
+ end_block_scope();
return token;
}
@@ -2806,15 +2843,15 @@ static struct token *parse_function_body(struct token *token, struct symbol *dec
decl->ctype.modifiers |= MOD_EXTERN;
stmt = start_function(decl);
-
*p = stmt;
+
FOR_EACH_PTR (base_type->arguments, arg) {
declare_argument(arg, base_type);
} END_FOR_EACH_PTR(arg);
- token = compound_statement(token->next, stmt);
-
+ token = statement_list(token->next, &stmt->stmts);
end_function(decl);
+
if (!(decl->ctype.modifiers & MOD_INLINE))
add_symbol(list, decl);
check_declaration(decl);
diff --git a/parse.h b/parse.h
index 0742a2a8..5ac9a23b 100644
--- a/parse.h
+++ b/parse.h
@@ -72,6 +72,7 @@ struct statement {
};
struct /* labeled_struct */ {
struct symbol *label_identifier;
+ struct scope *label_scope;
struct statement *label_statement;
};
struct /* case_struct */ {
@@ -123,7 +124,8 @@ extern struct symbol_list *function_computed_target_list;
extern struct statement_list *function_computed_goto_list;
extern struct token *parse_expression(struct token *, struct expression **);
-extern struct symbol *label_symbol(struct token *token);
+extern struct symbol *label_symbol(struct token *token, int used);
+extern void check_label_usage(struct symbol *label, struct position use_pos);
extern int show_statement(struct statement *);
extern void show_statement_list(struct statement_list *, const char *);
diff --git a/scope.c b/scope.c
index 420c0f5a..fb587c47 100644
--- a/scope.c
+++ b/scope.c
@@ -36,6 +36,7 @@
static struct scope builtin_scope = { .next = &builtin_scope };
struct scope *block_scope = &builtin_scope, // regular automatic variables etc
+ *label_scope = NULL, // expr-stmt labels
*function_scope = &builtin_scope, // labels, arguments etc
*file_scope = &builtin_scope, // static
*global_scope = &builtin_scope; // externally visible
@@ -68,7 +69,6 @@ void rebind_scope(struct symbol *sym, struct scope *new)
static void start_scope(struct scope **s)
{
struct scope *scope = __alloc_scope(0);
- memset(scope, 0, sizeof(*scope));
scope->next = *s;
*s = scope;
}
@@ -77,7 +77,6 @@ void start_file_scope(void)
{
struct scope *scope = __alloc_scope(0);
- memset(scope, 0, sizeof(*scope));
scope->next = &builtin_scope;
file_scope = scope;
@@ -86,15 +85,16 @@ void start_file_scope(void)
block_scope = scope;
}
-void start_symbol_scope(void)
+void start_block_scope(void)
{
start_scope(&block_scope);
}
void start_function_scope(void)
{
- start_scope(&function_scope);
start_scope(&block_scope);
+ start_scope(&label_scope);
+ function_scope = label_scope;
}
static void remove_symbol_scope(struct symbol *sym)
@@ -131,7 +131,7 @@ void new_file_scope(void)
start_file_scope();
}
-void end_symbol_scope(void)
+void end_block_scope(void)
{
end_scope(&block_scope);
}
@@ -139,7 +139,28 @@ void end_symbol_scope(void)
void end_function_scope(void)
{
end_scope(&block_scope);
- end_scope(&function_scope);
+ end_label_scope();
+ function_scope = label_scope;
+}
+
+void start_label_scope(void)
+{
+ start_scope(&label_scope);
+}
+
+void end_label_scope(void)
+{
+ struct symbol *sym;
+
+ FOR_EACH_PTR(label_scope->symbols, sym) {
+ if (!sym->stmt || sym->used)
+ continue;
+ if (sym->label_modifiers & MOD_UNUSED)
+ continue;
+ warning(sym->pos, "unused label '%s'", show_ident(sym->ident));
+ } END_FOR_EACH_PTR(sym);
+
+ end_scope(&label_scope);
}
int is_outer_scope(struct scope *scope)
@@ -151,3 +172,12 @@ int is_outer_scope(struct scope *scope)
return 1;
}
+int is_in_scope(struct scope *outer, struct scope *inner)
+{
+ while (inner != outer) {
+ if (inner == function_scope)
+ return 0;
+ inner = inner->next;
+ }
+ return 1;
+}
diff --git a/scope.h b/scope.h
index 3cad514a..36a56d6a 100644
--- a/scope.h
+++ b/scope.h
@@ -34,6 +34,7 @@ struct scope {
extern struct scope
*block_scope,
+ *label_scope,
*function_scope,
*file_scope,
*global_scope;
@@ -47,15 +48,20 @@ extern void start_file_scope(void);
extern void end_file_scope(void);
extern void new_file_scope(void);
-extern void start_symbol_scope(void);
-extern void end_symbol_scope(void);
+extern void start_block_scope(void);
+extern void end_block_scope(void);
extern void start_function_scope(void);
extern void end_function_scope(void);
+extern void start_label_scope(void);
+extern void end_label_scope(void);
+
extern void set_current_scope(struct symbol *);
extern void bind_scope(struct symbol *, struct scope *);
extern void rebind_scope(struct symbol *, struct scope *);
extern int is_outer_scope(struct scope *);
+extern int is_in_scope(struct scope *outer, struct scope *inner);
+
#endif
diff --git a/symbol.c b/symbol.c
index c2e6f0b4..7044ab3f 100644
--- a/symbol.c
+++ b/symbol.c
@@ -671,9 +671,8 @@ static void inherit_static(struct symbol *sym)
}
}
-void bind_symbol(struct symbol *sym, struct ident *ident, enum namespace ns)
+void bind_symbol_with_scope(struct symbol *sym, struct ident *ident, enum namespace ns, struct scope *scope)
{
- struct scope *scope;
if (sym->bound) {
sparse_error(sym->pos, "internal error: symbol type already bound");
return;
@@ -690,7 +689,6 @@ void bind_symbol(struct symbol *sym, struct ident *ident, enum namespace ns)
sym->ident = ident;
sym->bound = 1;
- scope = block_scope;
if (ns == NS_SYMBOL && toplevel(scope)) {
unsigned mod = MOD_ADDRESSABLE | MOD_TOPLEVEL;
@@ -704,11 +702,18 @@ void bind_symbol(struct symbol *sym, struct ident *ident, enum namespace ns)
}
sym->ctype.modifiers |= mod;
}
+ bind_scope(sym, scope);
+}
+
+void bind_symbol(struct symbol *sym, struct ident *ident, enum namespace ns)
+{
+ struct scope *scope = block_scope;;
+
if (ns == NS_MACRO)
scope = file_scope;
if (ns == NS_LABEL)
scope = function_scope;
- bind_scope(sym, scope);
+ bind_symbol_with_scope(sym, ident, ns, scope);
}
struct symbol *create_symbol(int stream, const char *name, int type, int namespace)
diff --git a/symbol.h b/symbol.h
index 92ccbddb..a16a27c2 100644
--- a/symbol.h
+++ b/symbol.h
@@ -166,10 +166,16 @@ struct symbol {
int (*handler)(struct stream *, struct token **, struct token *);
int normal;
};
+ struct /* NS_LABEL */ {
+ struct scope *label_scope;
+ struct position label_pos;
+ unsigned long label_modifiers;
+ };
struct /* NS_SYMBOL */ {
unsigned long offset;
int bit_size;
unsigned int bit_offset:8,
+ bogus_linear:1,
variadic:1,
initialized:1,
examined:1,
@@ -330,6 +336,7 @@ extern void show_type_list(struct symbol *);
extern void show_symbol_list(struct symbol_list *, const char *);
extern void add_symbol(struct symbol_list **, struct symbol *);
extern void bind_symbol(struct symbol *, struct ident *, enum namespace);
+extern void bind_symbol_with_scope(struct symbol *, struct ident *, enum namespace, struct scope *);
extern struct symbol *examine_symbol_type(struct symbol *);
extern struct symbol *examine_pointer_target(struct symbol *);
diff --git a/validation/__func__-scope.c b/validation/__func__-scope.c
new file mode 100644
index 00000000..508a8b91
--- /dev/null
+++ b/validation/__func__-scope.c
@@ -0,0 +1,8 @@
+static void foo(void)
+{
+ const char *name = ({ __func__; });
+}
+/*
+ * check-name: __func__'s scope
+ * check-command: sparse -Wall $file
+ */
diff --git a/validation/asm-goto-lables.c b/validation/asm-goto-labels.c
index ac2bf2ad..ac2bf2ad 100644
--- a/validation/asm-goto-lables.c
+++ b/validation/asm-goto-labels.c
diff --git a/validation/label-asm.c b/validation/label-asm.c
index 411020ac..b58d1e52 100644
--- a/validation/label-asm.c
+++ b/validation/label-asm.c
@@ -3,6 +3,7 @@
static void f(void)
{
barrier();
+ goto l;
l:
barrier();
}
diff --git a/validation/label-attr.c b/validation/label-attr.c
index a82d7bc9..81c4ac3c 100644
--- a/validation/label-attr.c
+++ b/validation/label-attr.c
@@ -1,6 +1,6 @@
static int foo(void)
{
- return 0;
+ goto rtattr_failure;
rtattr_failure: __attribute__ ((unused))
return -1;
}
diff --git a/validation/label-scope-cgoto.c b/validation/label-scope-cgoto.c
new file mode 100644
index 00000000..1edb9948
--- /dev/null
+++ b/validation/label-scope-cgoto.c
@@ -0,0 +1,82 @@
+void foo(void)
+{
+ void *p = &&l;
+ {
+l: ;
+ }
+ goto *p; // OK
+}
+
+void bar(void)
+{
+ void *p = &&l; // KO: 'jump' inside
+ ({
+l: 1;
+ });
+ goto *p;
+}
+
+void baz(void)
+{
+ void *p = &&l; // KO: 'jump' inside
+ 0 ? 1 : ({
+l: 1;
+ });
+ goto *p;
+}
+
+void qux(void)
+{
+ void *p = &&l; // KO: 'jump' inside + removed
+ 1 ? 1 : ({
+l: 1;
+ });
+ goto *p;
+}
+
+void quz(void)
+{
+ void *p;
+ p = &&l; // KO: undeclared
+ goto *p;
+}
+
+void qxu(void)
+{
+ void *p;
+ ({
+l: 1;
+ });
+ p = &&l; // KO: 'jump' inside
+ goto *p;
+}
+
+void qzu(void)
+{
+ void *p;
+ 1 ? 1 : ({
+l: 1;
+ });
+ p = &&l; // KO: 'jump' inside + removed
+ goto *p;
+}
+
+
+/*
+ * check-name: label-scope-cgoto
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+label-scope-cgoto.c:12:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:14:1: label 'l' defined here
+label-scope-cgoto.c:21:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:23:1: label 'l' defined here
+label-scope-cgoto.c:30:19: error: label 'l' used outside statement expression
+label-scope-cgoto.c:32:1: label 'l' defined here
+label-scope-cgoto.c:50:13: error: label 'l' used outside statement expression
+label-scope-cgoto.c:48:1: label 'l' defined here
+label-scope-cgoto.c:60:13: error: label 'l' used outside statement expression
+label-scope-cgoto.c:58:1: label 'l' defined here
+label-scope-cgoto.c:40:13: error: label 'l' was not declared
+ * check-error-end
+ */
diff --git a/validation/label-scope.c b/validation/label-scope.c
index 7af3d916..0ffaaf4a 100644
--- a/validation/label-scope.c
+++ b/validation/label-scope.c
@@ -3,10 +3,7 @@ static int f(int n)
__label__ n;
n: return n;
}
-static int g(int n)
-{
-n: return n;
-}
+
/*
* check-name: __label__ scope
*/
diff --git a/validation/label-scope1.c b/validation/label-scope1.c
new file mode 100644
index 00000000..f2b1ae9b
--- /dev/null
+++ b/validation/label-scope1.c
@@ -0,0 +1,42 @@
+static void ok_top(void)
+{
+ __label__ l;
+l:
+ goto l;
+}
+
+static void ko_undecl(void)
+{
+ __label__ l;
+ goto l; // KO: undeclared
+}
+
+static void ok_local(void)
+{
+l:
+ {
+ __label__ l;
+l:
+ goto l;
+ }
+goto l;
+}
+
+static void ko_scope(void)
+{
+ {
+ __label__ l;
+l:
+ goto l;
+ }
+goto l; // KO: undeclared
+}
+
+/*
+ * check-name: label-scope1
+ *
+ * check-error-start
+label-scope1.c:11:9: error: label 'l' was not declared
+label-scope1.c:32:1: error: label 'l' was not declared
+ * check-error-end
+ */
diff --git a/validation/label-scope2.c b/validation/label-scope2.c
new file mode 100644
index 00000000..44864752
--- /dev/null
+++ b/validation/label-scope2.c
@@ -0,0 +1,31 @@
+static void ok_lvl2(void)
+{
+ __label__ l;
+
+ {
+ l:
+ goto l;
+ }
+}
+
+static void ko_expr2(void)
+{
+ {
+ __label__ a;
+
+ ({
+a:
+ 0;
+ });
+ goto a;
+ }
+}
+
+/*
+ * check-name: label-scope2
+ *
+ * check-error-start
+label-scope2.c:20:17: error: label 'a' used outside statement expression
+label-scope2.c:17:1: label 'a' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr0.c b/validation/label-stmt-expr0.c
new file mode 100644
index 00000000..5fc452ab
--- /dev/null
+++ b/validation/label-stmt-expr0.c
@@ -0,0 +1,38 @@
+void aft(void)
+{
+ ({
+l: 1;
+ });
+ goto l; // KO
+}
+
+void bef(void)
+{
+ goto l; // KO
+ ({
+l: 1;
+ });
+}
+
+void lab(void)
+{
+ __label__ l;
+ ({
+l: 1;
+ });
+ goto l; // KO
+}
+
+/*
+ * check-name: label-stmt-expr0
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+label-stmt-expr0.c:6:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:4:1: label 'l' defined here
+label-stmt-expr0.c:11:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:13:1: label 'l' defined here
+label-stmt-expr0.c:23:9: error: label 'l' used outside statement expression
+label-stmt-expr0.c:21:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr1.c b/validation/label-stmt-expr1.c
new file mode 100644
index 00000000..32a89aad
--- /dev/null
+++ b/validation/label-stmt-expr1.c
@@ -0,0 +1,28 @@
+static int foo(void)
+{
+ goto l;
+ ({
+l:
+ 0;
+ });
+}
+
+static void bar(void)
+{
+ ({
+l:
+ 0;
+ });
+ goto l;
+}
+
+/*
+ * check-name: label-stmt-expr1
+ *
+ * check-error-start
+label-stmt-expr1.c:3:9: error: label 'l' used outside statement expression
+label-stmt-expr1.c:5:1: label 'l' defined here
+label-stmt-expr1.c:16:9: error: label 'l' used outside statement expression
+label-stmt-expr1.c:13:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-stmt-expr2.c b/validation/label-stmt-expr2.c
new file mode 100644
index 00000000..8c54477a
--- /dev/null
+++ b/validation/label-stmt-expr2.c
@@ -0,0 +1,46 @@
+static int foo(void)
+{
+ goto l;
+ ({
+l:
+ 0;
+ });
+ goto l;
+}
+
+static void bar(void)
+{
+ goto l;
+ goto l;
+ ({
+l:
+ 0;
+ });
+}
+
+static void baz(void)
+{
+ ({
+l:
+ 0;
+ });
+ goto l;
+ goto l;
+}
+
+/*
+ * check-name: label-stmt-expr2
+ *
+ * check-error-start
+label-stmt-expr2.c:3:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:5:1: label 'l' defined here
+label-stmt-expr2.c:8:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:5:1: label 'l' defined here
+label-stmt-expr2.c:13:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:16:1: label 'l' defined here
+label-stmt-expr2.c:27:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:24:1: label 'l' defined here
+label-stmt-expr2.c:28:9: error: label 'l' used outside statement expression
+label-stmt-expr2.c:24:1: label 'l' defined here
+ * check-error-end
+ */
diff --git a/validation/label-unused.c b/validation/label-unused.c
new file mode 100644
index 00000000..e3f255e1
--- /dev/null
+++ b/validation/label-unused.c
@@ -0,0 +1,29 @@
+static void foo(void)
+{
+l:
+ return;
+}
+
+static int bar(void)
+{
+ return ({
+l:
+ ;
+ 0;
+ });
+}
+
+static void baz(void)
+{
+l: __attribute__((unused));
+ return;
+}
+
+/*
+ * check-name: label-unused
+ *
+ * check-error-start
+label-unused.c:3:1: warning: unused label 'l'
+label-unused.c:10:1: warning: unused label 'l'
+ * check-error-end
+ */
diff --git a/validation/linear/goto-invalid.c b/validation/linear/goto-invalid.c
new file mode 100644
index 00000000..860b32a4
--- /dev/null
+++ b/validation/linear/goto-invalid.c
@@ -0,0 +1,18 @@
+static void foo(void)
+{
+ goto return;
+}
+
+void bar(void)
+{
+ goto neverland;
+}
+
+/*
+ * check-name: goto-invalid
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/goto-stmt-expr-conditional.c b/validation/linear/goto-stmt-expr-conditional.c
new file mode 100644
index 00000000..bbfcb3eb
--- /dev/null
+++ b/validation/linear/goto-stmt-expr-conditional.c
@@ -0,0 +1,27 @@
+int t(void)
+{
+ goto inside;
+ return 1 ? 2 : ({
+inside:
+ return 3;
+ 4;
+ });
+}
+
+void f(int x, int y)
+{
+ 1 ? x : ({
+a:
+ y;
+ });
+ goto a;
+}
+
+/*
+ * check-name: goto-stmt-expr-conditional
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/goto-stmt-expr-short-circuit.c b/validation/linear/goto-stmt-expr-short-circuit.c
new file mode 100644
index 00000000..a5953e73
--- /dev/null
+++ b/validation/linear/goto-stmt-expr-short-circuit.c
@@ -0,0 +1,31 @@
+int foo(int p)
+{
+ goto inside;
+ if (0 && ({
+inside:
+ return 1;
+ 2;
+ }))
+ return 3;
+ return 4;
+}
+
+int bar(int p)
+{
+ if (0 && ({
+inside:
+ return 1;
+ 2;
+ }))
+ return 3;
+ goto inside;
+}
+
+/*
+ * check-name: goto-stmt-expr-short-circuit
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/linear/label-scope-cgoto.c b/validation/linear/label-scope-cgoto.c
new file mode 100644
index 00000000..0eba05ae
--- /dev/null
+++ b/validation/linear/label-scope-cgoto.c
@@ -0,0 +1,10 @@
+#include <label-scope-cgoto.c>
+
+/*
+ * check-name: linear/label-scope-cgoto
+ * check-command: test-linearize -Wno-decl -I. $file
+ *
+ * check-error-ignore
+ * check-output-ignore
+ * check-output-excludes: END
+ */
diff --git a/validation/discarded-label-statement.c b/validation/linear/label-stmt-dropped.c
index b4e58ac6..74e0f2e6 100644
--- a/validation/discarded-label-statement.c
+++ b/validation/linear/label-stmt-dropped.c
@@ -11,11 +11,13 @@ start:
r += a;
r += b;
+ if (!r)
+ goto start;
return r;
}
/*
- * check-name: discarded-label-statement
+ * check-name: label-stmt-dropped
* check-command: test-linearize $file
*
* check-output-ignore
diff --git a/validation/label-expr.c b/validation/linear/label-stmt-expr0.c
index e578ed00..ff3c0980 100644
--- a/validation/label-expr.c
+++ b/validation/linear/label-stmt-expr0.c
@@ -3,12 +3,12 @@ int foo(void)
{
int r;
- r = ({ label: 1; });
+ r = ({ goto label; label: 1; });
return r;
}
/*
- * check-name: label-expr
+ * check-name: label-stmt-expr0
* check-command: test-linearize $file
* check-output-ignore
*
diff --git a/validation/linear/unreachable-label0.c b/validation/linear/label-unreachable.c
index 695e5cb0..a44e1211 100644
--- a/validation/linear/unreachable-label0.c
+++ b/validation/linear/label-unreachable.c
@@ -10,9 +10,10 @@ label:
}
/*
- * check-name: unreachable-label0
+ * check-name: label-unreachable
* check-command: test-linearize $file
*
+ * check-error-ignore
* check-output-ignore
* check-output-contains: ret\\.
* check-output-excludes: END
diff --git a/validation/nested-functions.c b/validation/nested-functions.c
new file mode 100644
index 00000000..349edb5a
--- /dev/null
+++ b/validation/nested-functions.c
@@ -0,0 +1,43 @@
+static int test_ok(int a, int b)
+{
+ int nested_ok(int i)
+ {
+ return i * 2;
+ }
+ return nested_ok(b);
+}
+
+static int test_ko(int a, int b)
+{
+ int nested_ko(int i)
+ {
+ return i * 2 + a;
+ }
+ return nested_ko(b);
+}
+
+static int test_inline(int a, int b)
+{
+ inline int nested(int i)
+ {
+ return i * 2;
+ }
+ return nested(b);
+}
+
+static int test_inline_ko(int a, int b)
+{
+ inline int nested(int i)
+ {
+ return i * 2 + a;
+ }
+ return nested(b);
+}
+
+/*
+ * check-name: nested-functions
+ *
+ * check-error-start
+nested-functions.c:32:32: warning: unreplaced symbol 'a'
+ * check-error-end
+ */
diff --git a/validation/typeof-safe.c b/validation/typeof-safe.c
index 614863fb..797c759f 100644
--- a/validation/typeof-safe.c
+++ b/validation/typeof-safe.c
@@ -2,22 +2,35 @@
static void test_safe(void)
{
- int __safe obj, *ptr;
- typeof(obj) var = obj;
- typeof(ptr) ptr2 = ptr;
+ int obj;
+ int __safe *ptr;
+
+ int __safe *ptr2 = ptr;
+ typeof(ptr) ptr3 = ptr;
typeof(*ptr) var2 = obj;
- typeof(*ptr) *ptr3 = ptr;
- typeof(obj) *ptr4 = ptr;
+ int __safe var3 = obj;
+ int *ptr4 = &obj;
+ int *ptr5 = ptr; // KO
+
+ typeof(*ptr) sobj;
+ typeof(&sobj) ptr6 = &obj;
+ typeof(&sobj) ptr7 = ptr; // KO
+
obj = obj;
ptr = ptr;
- ptr = &obj;
obj = *ptr;
+ ptr = (int __safe *) &obj;
}
/*
* check-name: typeof-safe
- * check-known-to-fail
*
* check-error-start
+typeof-safe.c:13:21: warning: incorrect type in initializer (different modifiers)
+typeof-safe.c:13:21: expected int *ptr5
+typeof-safe.c:13:21: got int [safe] *ptr
+typeof-safe.c:17:30: warning: incorrect type in initializer (different modifiers)
+typeof-safe.c:17:30: expected int *ptr7
+typeof-safe.c:17:30: got int [safe] *ptr
* check-error-end
*/