diff options
31 files changed, 617 insertions, 63 deletions
@@ -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) @@ -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(); @@ -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); @@ -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 *); @@ -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; +} @@ -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 @@ -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) @@ -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 */ |