diff options
40 files changed, 701 insertions, 147 deletions
diff --git a/Documentation/TODO.md b/Documentation/TODO.md index cbda1c39..4344a1dc 100644 --- a/Documentation/TODO.md +++ b/Documentation/TODO.md @@ -24,15 +24,9 @@ Core - add the sym into a list and - recalculate the addressability before memops's SSA conversion * bool_ctype should be split into internal 1-bit / external 8-bit -* Previous declarations and the definition need to be merged. For example, - in the code here below, the function definition is **not** static: - ``` - static void foo(void); - void foo(void) { ... } - ``` Testsuite --------- +--------- * there are more than 50 failing tests. They should be fixed (but most are non-trivial to fix). @@ -84,9 +78,13 @@ Longer term/to investigate * should support "-Werror=..." ? * All warning messages should include the option how to disable it. For example: + "warning: Variable length array is used." + should be something like: + "warning: Variable length array is used. (-Wno-vla)" + * ptrlists must have elements be removed while being iterated but this is hard to insure it is not done. * having 'struct symbol' used to represent symbols *and* types is diff --git a/Documentation/nocast-vs-bitwise.md b/Documentation/nocast-vs-bitwise.md index b649abcd..9ba5a789 100644 --- a/Documentation/nocast-vs-bitwise.md +++ b/Documentation/nocast-vs-bitwise.md @@ -1,4 +1,5 @@ -# __nocast vs __bitwise +__nocast vs __bitwise +===================== `__nocast` warns about explicit or implicit casting to different types. HOWEVER, it doesn't consider two 32-bit integers to be different @@ -16,25 +17,26 @@ harder to lose the type by mistake. So the basic rule is: - - `__nocast` on its own tends to be more useful for *big* integers -that still need to act like integers, but you want to make it much -less likely that they get truncated by mistake. So a 64-bit integer -that you don't want to mistakenly/silently be returned as `int`, for -example. But they mix well with random integer types, so you can add -to them etc without using anything special. However, that mixing also -means that the `__nocast` really gets lost fairly easily. - - - `__bitwise` is for *unique types* that cannot be mixed with other -types, and that you'd never want to just use as a random integer (the -integer `0` is special, though, and gets silently accepted - it's -kind of like `NULL` for pointers). So `gfp_t` or the `safe endianness` -types would be `__bitwise`: you can only operate on them by doing -specific operations that know about *that* particular type. +- `__nocast` on its own tends to be more useful for *big* integers + that still need to act like integers, but you want to make it much + less likely that they get truncated by mistake. So a 64-bit integer + that you don't want to mistakenly/silently be returned as `int`, for + example. But they mix well with random integer types, so you can add + to them etc without using anything special. However, that mixing also + means that the `__nocast` really gets lost fairly easily. + +- `__bitwise` is for *unique types* that cannot be mixed with other + types, and that you'd never want to just use as a random integer (the + integer `0` is special, though, and gets silently accepted - it's + kind of like `NULL` for pointers). So `gfp_t` or the `safe endianness` + types would be `__bitwise`: you can only operate on them by doing + specific operations that know about *that* particular type. Generally, you want `__bitwise` if you are looking for type safety. `__nocast` really is pretty weak. -## Reference: +Reference: +---------- * Linus' e-mail about `__nocast` vs `__bitwise`: diff --git a/Documentation/sphinx/cdoc.py b/Documentation/sphinx/cdoc.py index 318e9b23..73c128cb 100755 --- a/Documentation/sphinx/cdoc.py +++ b/Documentation/sphinx/cdoc.py @@ -269,7 +269,7 @@ if __name__ == '__main__': dump_doc(extract(sys.stdin, '<stdin>')) -from sphinx.ext.autodoc import AutodocReporter +from sphinx.util.docutils import switch_source_input import docutils import os class CDocDirective(docutils.parsers.rst.Directive): @@ -294,13 +294,13 @@ class CDocDirective(docutils.parsers.rst.Directive): ## let parse this new reST content memo = self.state.memo - save = memo.reporter, memo.title_styles, memo.section_level - memo.reporter = AutodocReporter(lst, memo.reporter) + save = memo.title_styles, memo.section_level node = docutils.nodes.section() try: - self.state.nested_parse(lst, 0, node, match_titles=1) + with switch_source_input(self.state, lst): + self.state.nested_parse(lst, 0, node, match_titles=1) finally: - memo.reporter, memo.title_styles, memo.section_level = save + memo.title_styles, memo.section_level = save return node.children def setup(app): @@ -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(); @@ -113,7 +113,7 @@ enum { #elif defined(__sun__) || defined(__sun) #define OS_NATIVE OS_SUNOS #elif defined(__unix__) || defined(__unix) -#define OS_UNIX OS_UNIX +#define OS_NATIVE OS_UNIX #else #define OS_NATIVE OS_UNKNOWN #endif @@ -84,7 +84,6 @@ typedef struct token *attr_t(struct token *, struct symbol *, static attr_t attribute_packed, attribute_aligned, attribute_modifier, attribute_function, - attribute_ext_visible, attribute_bitwise, attribute_address_space, attribute_context, attribute_designated_init, @@ -389,10 +388,6 @@ static struct symbol_op attr_fun_op = { .attribute = attribute_function, }; -static struct symbol_op ext_visible_op = { - .attribute = attribute_ext_visible, -}; - static struct symbol_op attr_bitwise_op = { .attribute = attribute_bitwise, }; @@ -571,6 +566,10 @@ static struct init_keyword { { "__noderef__",NS_KEYWORD, MOD_NODEREF, .op = &attr_mod_op }, { "safe", NS_KEYWORD, MOD_SAFE, .op = &attr_mod_op }, { "__safe__", NS_KEYWORD, MOD_SAFE, .op = &attr_mod_op }, + { "unused", NS_KEYWORD, MOD_UNUSED, .op = &attr_mod_op }, + { "__unused__", NS_KEYWORD, MOD_UNUSED, .op = &attr_mod_op }, + { "externally_visible", NS_KEYWORD, MOD_EXT_VISIBLE,.op = &attr_mod_op }, + { "__externally_visible__", NS_KEYWORD,MOD_EXT_VISIBLE,.op = &attr_mod_op }, { "force", NS_KEYWORD, .op = &attr_force_op }, { "__force__", NS_KEYWORD, .op = &attr_force_op }, { "bitwise", NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op }, @@ -588,8 +587,8 @@ static struct init_keyword { {"const", NS_KEYWORD, MOD_PURE, .op = &attr_fun_op }, {"__const", NS_KEYWORD, MOD_PURE, .op = &attr_fun_op }, {"__const__", NS_KEYWORD, MOD_PURE, .op = &attr_fun_op }, - {"externally_visible", NS_KEYWORD, .op = &ext_visible_op }, - {"__externally_visible__", NS_KEYWORD, .op = &ext_visible_op }, + {"gnu_inline", NS_KEYWORD, MOD_GNU_INLINE, .op = &attr_fun_op }, + {"__gnu_inline__",NS_KEYWORD, MOD_GNU_INLINE, .op = &attr_fun_op }, { "mode", NS_KEYWORD, .op = &mode_op }, { "__mode__", NS_KEYWORD, .op = &mode_op }, @@ -722,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; @@ -1127,11 +1128,16 @@ static struct token *attribute_aligned(struct token *token, struct symbol *attr, return token; } +static void apply_mod(struct position *pos, unsigned long *mods, unsigned long mod) +{ + if (*mods & mod & ~MOD_DUP_OK) + warning(*pos, "duplicate %s", modifier_string(mod)); + *mods |= mod; +} + static void apply_qualifier(struct position *pos, struct ctype *ctx, unsigned long qual) { - if (ctx->modifiers & qual) - warning(*pos, "duplicate %s", modifier_string(qual)); - ctx->modifiers |= qual; + apply_mod(pos, &ctx->modifiers, qual); } static struct token *attribute_modifier(struct token *token, struct symbol *attr, struct decl_state *ctx) @@ -1142,16 +1148,7 @@ static struct token *attribute_modifier(struct token *token, struct symbol *attr static struct token *attribute_function(struct token *token, struct symbol *attr, struct decl_state *ctx) { - unsigned long mod = attr->ctype.modifiers; - if (ctx->f_modifiers & mod) - warning(token->pos, "duplicate %s", modifier_string(mod)); - ctx->f_modifiers |= mod; - return token; -} - -static struct token *attribute_ext_visible(struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - ctx->is_ext_visible = 1; + apply_mod(&token->pos, &ctx->f_modifiers, attr->ctype.modifiers); return token; } @@ -1382,7 +1379,7 @@ static const char *storage_class[] = [SForced] = "[force]" }; -static unsigned long storage_modifiers(struct decl_state *ctx) +static unsigned long decl_modifiers(struct decl_state *ctx) { static unsigned long mod[SMax] = { @@ -1391,15 +1388,16 @@ static unsigned long storage_modifiers(struct decl_state *ctx) [SStatic] = MOD_STATIC, [SRegister] = MOD_REGISTER }; - return mod[ctx->storage_class] | (ctx->is_inline ? MOD_INLINE : 0) - | (ctx->is_tls ? MOD_TLS : 0) - | (ctx->is_ext_visible ? MOD_EXT_VISIBLE : 0); + unsigned long mods = ctx->ctype.modifiers & MOD_DECLARE; + ctx->ctype.modifiers &= ~MOD_DECLARE; + return mod[ctx->storage_class] | mods; } static void set_storage_class(struct position *pos, struct decl_state *ctx, int class) { + int is_tls = ctx->ctype.modifiers & MOD_TLS; /* __thread can be used alone, or with extern or static */ - if (ctx->is_tls && (class != SStatic && class != SExtern)) { + if (is_tls && (class != SStatic && class != SExtern)) { sparse_error(*pos, "__thread can only be used alone, or with " "extern or static"); return; @@ -1450,7 +1448,7 @@ static struct token *thread_specifier(struct token *next, struct decl_state *ctx /* This GCC extension can be used alone, or with extern or static */ if (!ctx->storage_class || ctx->storage_class == SStatic || ctx->storage_class == SExtern) { - ctx->is_tls = 1; + apply_qualifier(&next->pos, &ctx->ctype, MOD_TLS); } else { sparse_error(next->pos, "__thread can only be used alone, or " "with extern or static"); @@ -1467,7 +1465,7 @@ static struct token *attribute_force(struct token *token, struct symbol *attr, s static struct token *inline_specifier(struct token *next, struct decl_state *ctx) { - ctx->is_inline = 1; + apply_qualifier(&next->pos, &ctx->ctype, MOD_INLINE); return next; } @@ -1670,7 +1668,7 @@ static struct token *declaration_specifiers(struct token *token, struct decl_sta } } token = token->next; - if (s->op->declarator) + if (s->op->declarator) // Note: this eats attributes token = s->op->declarator(token, ctx); if (s->op->type & KW_EXACT) { ctx->ctype.base_type = s->ctype.base_type; @@ -1997,7 +1995,7 @@ static struct token *declaration_list(struct token *token, struct symbol_list ** unsigned long mod; token = declaration_specifiers(token, &ctx); - mod = storage_modifiers(&ctx); + mod = decl_modifiers(&ctx); saved = ctx.ctype; for (;;) { struct symbol *decl = alloc_symbol(token->pos, SYM_NODE); @@ -2050,7 +2048,7 @@ static struct token *parameter_declaration(struct token *token, struct symbol *s token = handle_attributes(token, &ctx, KW_ATTRIBUTE); apply_modifiers(token->pos, &ctx); sym->ctype = ctx.ctype; - sym->ctype.modifiers |= storage_modifiers(&ctx); + sym->ctype.modifiers |= decl_modifiers(&ctx); sym->endpos = token->pos; sym->forced_arg = ctx.storage_class == SForced; return token; @@ -2131,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, ',')); @@ -2222,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); @@ -2237,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) @@ -2282,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); @@ -2302,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) @@ -2472,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; @@ -2480,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"); @@ -2521,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); @@ -2532,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 @@ -2541,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"); } @@ -2565,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, ',')) @@ -2658,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; } @@ -2817,15 +2850,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); @@ -2960,7 +2993,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis /* Parse declaration-specifiers, if any */ token = declaration_specifiers(token, &ctx); - mod = storage_modifiers(&ctx); + mod = decl_modifiers(&ctx); decl = alloc_symbol(token->pos, SYM_NODE); /* Just a type declaration? */ if (match_op(token, ';')) { @@ -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 diff --git a/show-parse.c b/show-parse.c index 8a145b88..eb71b650 100644 --- a/show-parse.c +++ b/show-parse.c @@ -119,28 +119,30 @@ const char *modifier_string(unsigned long mod) static struct mod_name mod_names[] = { {MOD_AUTO, "auto"}, + {MOD_EXTERN, "extern"}, {MOD_REGISTER, "register"}, {MOD_STATIC, "static"}, - {MOD_EXTERN, "extern"}, + {MOD_INLINE, "inline"}, {MOD_CONST, "const"}, - {MOD_VOLATILE, "volatile"}, {MOD_RESTRICT, "restrict"}, - {MOD_ATOMIC, "[atomic]"}, - {MOD_SIGNED, "[signed]"}, - {MOD_UNSIGNED, "[unsigned]"}, - {MOD_TLS, "[tls]"}, - {MOD_INLINE, "inline"}, + {MOD_VOLATILE, "volatile"}, {MOD_ADDRESSABLE, "[addressable]"}, + {MOD_ASSIGNED, "[assigned]"}, + {MOD_ATOMIC, "[atomic]"}, + {MOD_BITWISE, "[bitwise]"}, + {MOD_EXPLICITLY_SIGNED, "[explicitly-signed]"}, + {MOD_GNU_INLINE, "[gnu_inline]"}, {MOD_NOCAST, "[nocast]"}, {MOD_NODEREF, "[noderef]"}, - {MOD_TOPLEVEL, "[toplevel]"}, - {MOD_ASSIGNED, "[assigned]"}, - {MOD_SAFE, "[safe]"}, - {MOD_USERTYPE, "[usertype]"}, {MOD_NORETURN, "[noreturn]"}, - {MOD_EXPLICITLY_SIGNED, "[explicitly-signed]"}, - {MOD_BITWISE, "[bitwise]"}, {MOD_PURE, "[pure]"}, + {MOD_SAFE, "[safe]"}, + {MOD_SIGNED, "[signed]"}, + {MOD_TLS, "[tls]"}, + {MOD_TOPLEVEL, "[toplevel]"}, + {MOD_UNSIGNED, "[unsigned]"}, + {MOD_UNUSED, "[unused]"}, + {MOD_USERTYPE, "[usertype]"}, }; for (i = 0; i < ARRAY_SIZE(mod_names); i++) { @@ -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) @@ -108,8 +108,7 @@ struct decl_state { struct ident **ident; struct symbol_op *mode; unsigned long f_modifiers; // function attributes - unsigned char prefer_abstract, is_inline, storage_class, is_tls; - unsigned char is_ext_visible; + unsigned char prefer_abstract, storage_class; unsigned char autotype; }; @@ -167,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, @@ -229,14 +234,14 @@ struct symbol { #define MOD_UNSIGNED 0x00004000 #define MOD_EXPLICITLY_SIGNED 0x00008000 - // MOD UNUSED 0x00010000 +#define MOD_GNU_INLINE 0x00010000 #define MOD_USERTYPE 0x00020000 // MOD UNUSED 0x00040000 // MOD UNUSED 0x00080000 // MOD UNUSED 0x00100000 // MOD UNUSED 0x00200000 - // MOD UNUSED 0x00400000 +#define MOD_UNUSED 0x00400000 #define MOD_SAFE 0x00800000 // non-null/non-trapping pointer #define MOD_PURE 0x01000000 #define MOD_BITWISE 0x02000000 @@ -252,7 +257,7 @@ struct symbol { #define MOD_ESIGNED (MOD_SIGNED | MOD_EXPLICITLY_SIGNED) #define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED) #define MOD_SPECIFIER MOD_SIGNEDNESS -#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED | MOD_EXT_VISIBLE) +#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED | MOD_EXT_VISIBLE | MOD_UNUSED | MOD_GNU_INLINE) #define MOD_QUALIFIER (MOD_CONST | MOD_VOLATILE | MOD_RESTRICT) #define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_ATOMIC | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST) /* modifiers preserved by typeof() operator */ @@ -261,6 +266,11 @@ struct symbol { #define MOD_FUN_ATTR (MOD_PURE|MOD_NORETURN) /* like cvr-qualifiers but 'reversed' (OK: source <= target) */ #define MOD_REV_QUAL (MOD_PURE|MOD_NORETURN) +/* do not warn when these are duplicated */ +#define MOD_DUP_OK (MOD_UNUSED|MOD_GNU_INLINE) +/* must be part of the declared symbol, not its type */ +#define MOD_DECLARE (MOD_STORAGE|MOD_INLINE|MOD_TLS|MOD_GNU_INLINE|MOD_UNUSED|MOD_PURE|MOD_NORETURN|MOD_EXT_VISIBLE) + /* Current parsing/evaluation function */ @@ -326,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/attr-visible.c b/validation/attr-visible.c index 38ee8575..ce35e4e5 100644 --- a/validation/attr-visible.c +++ b/validation/attr-visible.c @@ -9,5 +9,4 @@ int flag __visible; /* * check-name: attr-visible * check-command: sparse -Wdecl $file - * check-known-to-fail */ diff --git a/validation/attr-visible2.c b/validation/attr-visible2.c index 62949b47..98918169 100644 --- a/validation/attr-visible2.c +++ b/validation/attr-visible2.c @@ -6,5 +6,4 @@ int arr[2] __visible; /* * check-name: attr-visible-after * check-command: sparse -Wdecl $file - * check-known-to-fail */ diff --git a/validation/cond_expr2.c b/validation/cond_expr2.c index 5e974cfa..a5d96576 100644 --- a/validation/cond_expr2.c +++ b/validation/cond_expr2.c @@ -16,7 +16,7 @@ cond_expr2.c:6:11: warning: incorrect type in assignment (different modifiers) cond_expr2.c:6:11: expected void volatile *extern [addressable] [toplevel] q cond_expr2.c:6:11: got void const volatile * cond_expr2.c:8:11: warning: incorrect type in assignment (different modifiers) -cond_expr2.c:8:11: expected int volatile *extern [addressable] [toplevel] [assigned] r +cond_expr2.c:8:11: expected int volatile *extern [addressable] [assigned] [toplevel] r cond_expr2.c:8:11: got int const volatile * * check-error-end */ diff --git a/validation/function-redecl.c b/validation/function-redecl.c index 03151359..d0d844a5 100644 --- a/validation/function-redecl.c +++ b/validation/function-redecl.c @@ -51,11 +51,11 @@ void arg_vararg(int a, ...) { } /* check-should-fail */ function-redecl.c:5:6: error: symbol 'ret_type' redeclared with different type (different base types): function-redecl.c:5:6: void extern [addressable] [toplevel] ret_type( ... ) function-redecl.c:4:5: note: previously declared as: -function-redecl.c:4:5: int extern [signed] [addressable] [toplevel] ret_type( ... ) +function-redecl.c:4:5: int extern [addressable] [signed] [toplevel] ret_type( ... ) function-redecl.c:9:11: error: symbol 'ret_const' redeclared with different type (different modifiers): -function-redecl.c:9:11: int extern const [signed] [addressable] [toplevel] ret_const( ... ) +function-redecl.c:9:11: int extern const [addressable] [signed] [toplevel] ret_const( ... ) function-redecl.c:8:5: note: previously declared as: -function-redecl.c:8:5: int extern [signed] [addressable] [toplevel] ret_const( ... ) +function-redecl.c:8:5: int extern [addressable] [signed] [toplevel] ret_const( ... ) function-redecl.c:13:13: error: symbol 'ret_as' redeclared with different type (different address spaces): function-redecl.c:13:13: void <asn:1> *extern [addressable] [toplevel] ret_as( ... ) function-redecl.c:12:6: note: previously declared as: 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 */ |