aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--parse.c49
-rw-r--r--symbol.h3
-rw-r--r--validation/function-attribute-inner.c1
-rw-r--r--validation/function-attribute-pointer.c1
4 files changed, 28 insertions, 26 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);
diff --git a/symbol.h b/symbol.h
index 2465d6d8..d8a4f3b6 100644
--- a/symbol.h
+++ b/symbol.h
@@ -107,6 +107,7 @@ struct decl_state {
struct ctype ctype;
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;
};
@@ -251,7 +252,7 @@ struct symbol {
#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
/* modifiers preserved by typeof() operator */
#define MOD_TYPEOF (MOD_QUALIFIER | MOD_NOCAST | MOD_SPECIFIER)
-/* modifiers for funtion attributes */
+/* modifiers for function attributes */
#define MOD_FUN_ATTR (MOD_PURE|MOD_NORETURN)
/* like cvr-qualifiers but 'reversed' (OK: source <= target) */
#define MOD_REV_QUAL (MOD_PURE|MOD_NORETURN)
diff --git a/validation/function-attribute-inner.c b/validation/function-attribute-inner.c
index 178c7c01..3a8a8407 100644
--- a/validation/function-attribute-inner.c
+++ b/validation/function-attribute-inner.c
@@ -6,5 +6,4 @@ _Static_assert([void (__noreturn *)(void)] == [typeof(&fun)], "");
/*
* check-name: function-attribute-inner
- * check-known-to-fail
*/
diff --git a/validation/function-attribute-pointer.c b/validation/function-attribute-pointer.c
index 27f43bfb..fd08ac71 100644
--- a/validation/function-attribute-pointer.c
+++ b/validation/function-attribute-pointer.c
@@ -21,7 +21,6 @@ static void foo(void)
/*
* check-name: function-attribute-pointer
- * check-known-to-fail
*
* check-error-start
function-attribute-pointer.c:14:20: warning: incorrect type in argument 1 (different modifiers)