diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2019-11-17 02:23:58 +0100 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2019-11-20 21:36:50 +0100 |
| commit | 9305d48da0890d578254bd0e671e55a30b77ced0 (patch) | |
| tree | 1bcc974cd75b96ba6d489e3f6b59742011f1ab69 /parse.c | |
| parent | 009181de300b2f0e6f9e64d4694e07aa12808c57 (diff) | |
| download | sparse-dev-9305d48da0890d578254bd0e671e55a30b77ced0.tar.gz | |
propagate function modifiers only to functions
Function attributes need to be parsed differently
than the usual specifiers: For example, in code like:
#define __noreturn __attribute__((noreturn))
__noreturn void foo(int a);
the __noreturn attribute should apply to the function type
while a specifier like 'const' would apply to its return type.
The situation is quite similar to how storage specifiers
must not be handled by alloc_indirect_symbol().
However, the solution used for storage specifiers (apply the
modifier bits only after the declarator is reached: cfr.commit
233d4e17c ("function attributes apply to the function declaration"))
can't be used here (because the storage modifiers can be applied
to the outermost declarator and function attributes may be
applied more deeply if function pointers are present).
Fix this by:
1) reverting the previous storage-specifier-like solution
2) collect function specifiers MODs in a new separate
field in the declaration context (f_modifiers)
3) apply these modifiers when the declarator for the
function type is reached (note: it must not be
applied to the SYM_FN itself since this correspond
to the function's return type; it must be applied to
the parent node which can be a SYM_NODE or a SYM_PTR).
4) also apply these modifiers to the declared symbol,
if this symbol is a function declaration, to take
into account attributes which are placed at the end
of the declaration and not in front.
Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Fixes: 233d4e17c544e1de252aed8f409630599104dbc7
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'parse.c')
| -rw-r--r-- | parse.c | 49 |
1 files changed, 26 insertions, 23 deletions
@@ -82,6 +82,7 @@ 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, @@ -375,6 +376,10 @@ static struct symbol_op attr_mod_op = { .attribute = attribute_modifier, }; +static struct symbol_op attr_fun_op = { + .attribute = attribute_function, +}; + static struct symbol_op ext_visible_op = { .attribute = attribute_ext_visible, }; @@ -566,13 +571,13 @@ static struct init_keyword { { "__designated_init__", NS_KEYWORD, .op = &designated_init_op }, { "transparent_union", NS_KEYWORD, .op = &transparent_union_op }, { "__transparent_union__", NS_KEYWORD, .op = &transparent_union_op }, - { "noreturn", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op }, - { "__noreturn__", NS_KEYWORD, MOD_NORETURN, .op = &attr_mod_op }, - { "pure", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, - {"__pure__", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, - {"const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, - {"__const", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, - {"__const__", NS_KEYWORD, MOD_PURE, .op = &attr_mod_op }, + { "noreturn", NS_KEYWORD, MOD_NORETURN, .op = &attr_fun_op }, + { "__noreturn__", NS_KEYWORD, MOD_NORETURN, .op = &attr_fun_op }, + { "pure", NS_KEYWORD, MOD_PURE, .op = &attr_fun_op }, + {"__pure__", 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 }, + {"__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 }, @@ -1117,6 +1122,15 @@ static struct token *attribute_modifier(struct token *token, struct symbol *attr return token; } +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; @@ -1862,6 +1876,7 @@ static struct token *direct_declarator(struct token *token, struct decl_state *c enum kind kind = which_func(token, p, ctx->prefer_abstract); struct symbol *fn; fn = alloc_indirect_symbol(token->pos, ctype, SYM_FN); + ctype->modifiers |= ctx->f_modifiers; token = token->next; if (kind == K_R) token = identifier_list(token, fn); @@ -2900,21 +2915,6 @@ static struct token *toplevel_asm_declaration(struct token *token, struct symbol return token; } -static unsigned long declaration_modifiers(struct decl_state *ctx) -{ - unsigned long mods; - - // Storage modifiers only relates to the declaration - mods = storage_modifiers(ctx); - - // Function attributes also only relates to the declaration - // and must not be present in the function/return type. - mods |= ctx->ctype.modifiers & MOD_FUN_ATTR; - ctx->ctype.modifiers &=~ MOD_FUN_ATTR; - - return mods; -} - struct token *external_declaration(struct token *token, struct symbol_list **list, validate_decl_t validate_decl) { @@ -2935,7 +2935,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis /* Parse declaration-specifiers, if any */ token = declaration_specifiers(token, &ctx); - mod = declaration_modifiers(&ctx); + mod = storage_modifiers(&ctx); decl = alloc_symbol(token->pos, SYM_NODE); /* Just a type declaration? */ if (match_op(token, ';')) { @@ -2988,6 +2988,9 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis show_ident(decl->ident)); base_type->ctype.base_type = &int_ctype; } + /* apply attributes placed after the declarator */ + decl->ctype.modifiers |= ctx.f_modifiers; + /* K&R argument declaration? */ if (lookup_type(token)) return parse_k_r_arguments(token, decl, list); |
