aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/parse.c
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2019-11-17 02:23:58 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2019-11-20 21:36:50 +0100
commit9305d48da0890d578254bd0e671e55a30b77ced0 (patch)
tree1bcc974cd75b96ba6d489e3f6b59742011f1ab69 /parse.c
parent009181de300b2f0e6f9e64d4694e07aa12808c57 (diff)
downloadsparse-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.c49
1 files changed, 26 insertions, 23 deletions
diff --git a/parse.c b/parse.c
index 37ffede7..acae63af 100644
--- a/parse.c
+++ b/parse.c
@@ -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);