aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-05-21 17:40:33 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-05-21 17:40:33 +0200
commit18351292096b1b90ed7f3bc34459d371aa095588 (patch)
treee8d2bed28aab5770089cdd882bba3701bef2e5dd
parent386baba96aa18c8419c1ecea21a907ccc526a5fa (diff)
parentd1c0ce0393cab5442bdfbe8e03fd748d8dcdb2ed (diff)
downloadsparse-18351292096b1b90ed7f3bc34459d371aa095588.tar.gz
Merge branch 'fun-attr'
* improve handling of function attributes * separate modifiers into type/declaration * add support for attributes 'unused' & 'gnu_inline' * simplify parsing of inline/__tls/__visible
-rw-r--r--parse.c58
-rw-r--r--show-parse.c28
-rw-r--r--symbol.h14
-rw-r--r--validation/attr-visible.c1
-rw-r--r--validation/attr-visible2.c1
-rw-r--r--validation/cond_expr2.c2
-rw-r--r--validation/function-redecl.c6
7 files changed, 55 insertions, 55 deletions
diff --git a/parse.c b/parse.c
index a29c67c8..c1a72ae2 100644
--- a/parse.c
+++ b/parse.c
@@ -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 },
@@ -1127,11 +1126,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 +1146,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 +1377,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 +1386,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 +1446,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 +1463,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 +1666,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 +1993,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 +2046,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;
@@ -2953,7 +2949,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, ';')) {
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++) {
diff --git a/symbol.h b/symbol.h
index 18476582..92ccbddb 100644
--- a/symbol.h
+++ b/symbol.h
@@ -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;
};
@@ -229,14 +228,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 +251,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 +260,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 */
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: