aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2023-12-16 12:12:28 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2023-12-16 12:12:28 +0100
commiteac793a4ec5e4647e8301ddeb7c13ac78cb54fe1 (patch)
tree5cf657f7b256d5a05aaee7cf0a62125455915c48
parentce1a6720f69e6233ec9abd4e9aae5945e05fda41 (diff)
parent25e96501f249b27cb930a09aba5aeb33a047d14c (diff)
downloadsparse-dev-eac793a4ec5e4647e8301ddeb7c13ac78cb54fe1.tar.gz
Merge branch 'handle-cleanup-attr'
* teach Sparse about 'cleanup' attribute so that Smatch can handle it
-rw-r--r--gcc-attr-list.h1
-rw-r--r--parse.c31
-rw-r--r--symbol.h2
-rw-r--r--validation/parsing/attr-cleanup.c33
4 files changed, 66 insertions, 1 deletions
diff --git a/gcc-attr-list.h b/gcc-attr-list.h
index c7800175..928ea388 100644
--- a/gcc-attr-list.h
+++ b/gcc-attr-list.h
@@ -24,7 +24,6 @@ GCC_ATTR(brk_interrupt)
GCC_ATTR(callee_pop_aggregate_return)
GCC_ATTR(cb)
GCC_ATTR(cdecl)
-GCC_ATTR(cleanup)
GCC_ATTR(cmse_nonsecure_call)
GCC_ATTR(cmse_nonsecure_entry)
GCC_ATTR(cold)
diff --git a/parse.c b/parse.c
index 3d6fef7c..f868bf63 100644
--- a/parse.c
+++ b/parse.c
@@ -83,6 +83,7 @@ static attr_t
attribute_function,
attribute_bitwise,
attribute_address_space, attribute_context,
+ attribute_cleanup,
attribute_designated_init,
attribute_transparent_union, ignore_attribute,
attribute_mode, attribute_force;
@@ -361,6 +362,10 @@ static struct symbol_op aligned_op = {
.attribute = attribute_aligned,
};
+static struct symbol_op cleanup_op = {
+ .attribute = attribute_cleanup,
+};
+
static struct symbol_op attr_mod_op = {
.attribute = attribute_modifier,
};
@@ -537,6 +542,7 @@ static struct init_keyword {
/* Attributes */
D("packed", &packed_op),
D("aligned", &aligned_op),
+ D("cleanup", &cleanup_op),
D("nocast", &attr_mod_op, .mods = MOD_NOCAST),
D("noderef", &attr_mod_op, .mods = MOD_NODEREF),
D("safe", &attr_mod_op, .mods = MOD_SAFE),
@@ -1114,6 +1120,26 @@ static struct token *attribute_aligned(struct token *token, struct symbol *attr,
return token;
}
+static struct token *attribute_cleanup(struct token *token, struct symbol *attr, struct decl_state *ctx)
+{
+ struct expression *expr = NULL;
+
+ if (match_op(token, '(')) {
+ token = token->next;
+ if (match_op(token, ')'))
+ sparse_error(token->pos, "an argument is expected for attribute 'cleanup'");
+ else if (token_type(token) != TOKEN_IDENT)
+ sparse_error(token->pos, "argument is not an identifier");
+ token = primary_expression(token, &expr);
+ if (expr && expr->type == EXPR_SYMBOL)
+ ctx->cleanup = expr;
+ return expect(token, ')', "after attribute's argument'");
+ }
+
+ sparse_error(token->pos, "an argument is expected for attribute 'cleanup'");
+ return token;
+}
+
static void apply_mod(struct position *pos, unsigned long *mods, unsigned long mod)
{
if (*mods & mod & ~MOD_DUP_OK)
@@ -1899,6 +1925,7 @@ static struct token *declaration_list(struct token *token, struct symbol_list **
saved = ctx.ctype;
for (;;) {
struct symbol *decl = alloc_symbol(token->pos, SYM_NODE);
+ ctx.cleanup = NULL;
ctx.ident = &decl->ident;
token = declarator(token, &ctx);
@@ -1910,6 +1937,7 @@ static struct token *declaration_list(struct token *token, struct symbol_list **
decl->ctype = ctx.ctype;
decl->ctype.modifiers |= mod;
+ decl->cleanup = ctx.cleanup;
decl->endpos = token->pos;
add_symbol(list, decl);
if (!match_op(token, ','))
@@ -2924,6 +2952,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
decl->ctype = ctx.ctype;
decl->ctype.modifiers |= mod;
+ decl->cleanup = ctx.cleanup;
decl->endpos = token->pos;
/* Just a type declaration? */
@@ -3041,6 +3070,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
ident = NULL;
decl = alloc_symbol(token->pos, SYM_NODE);
ctx.ctype = saved;
+ ctx.cleanup = NULL;
token = handle_attributes(token, &ctx);
token = declarator(token, &ctx);
token = handle_asm_name(token, &ctx);
@@ -3048,6 +3078,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis
apply_modifiers(token->pos, &ctx);
decl->ctype = ctx.ctype;
decl->ctype.modifiers |= mod;
+ decl->cleanup = ctx.cleanup;
decl->endpos = token->pos;
if (!ident) {
sparse_error(token->pos, "expected identifier name in type definition");
diff --git a/symbol.h b/symbol.h
index 5270fcd7..88130c15 100644
--- a/symbol.h
+++ b/symbol.h
@@ -107,6 +107,7 @@ struct decl_state {
struct ctype ctype;
struct ident **ident;
struct symbol_op *mode;
+ struct expression *cleanup;
unsigned long f_modifiers; // function attributes
unsigned long storage_class;
unsigned char prefer_abstract;
@@ -204,6 +205,7 @@ struct symbol {
struct statement *inline_stmt;
struct symbol_list *inline_symbol_list;
struct expression *initializer;
+ struct expression *cleanup;
struct entrypoint *ep;
struct symbol *definition;
};
diff --git a/validation/parsing/attr-cleanup.c b/validation/parsing/attr-cleanup.c
new file mode 100644
index 00000000..ac64649c
--- /dev/null
+++ b/validation/parsing/attr-cleanup.c
@@ -0,0 +1,33 @@
+#define __cleanup(F) __attribute__((__cleanup__(F)))
+
+void fun(int *ptr);
+
+int test(int n);
+int test(int n)
+{
+ int var __attribute__((cleanup(fun))) = 1;
+ int alt __cleanup(fun) = 2;
+ int mis __cleanup(0) = 3;
+ int non __attribute__((cleanup));
+ int mis __attribute__((cleanup()));
+ int two __attribute__((cleanup(fun, fun)));
+
+ for (int i __cleanup(fun) = 0; i < n; i++)
+ ;
+
+ var = 5;
+ return 0;
+}
+
+/*
+ * check-name: attr-cleanup
+ * check-command: sparse -Wunknown-attribute $file
+ *
+ * check-error-start
+parsing/attr-cleanup.c:10:17: error: argument is not an identifier
+parsing/attr-cleanup.c:11:39: error: an argument is expected for attribute 'cleanup'
+parsing/attr-cleanup.c:12:40: error: an argument is expected for attribute 'cleanup'
+parsing/attr-cleanup.c:13:43: error: Expected ) after attribute's argument'
+parsing/attr-cleanup.c:13:43: error: got ,
+ * check-error-end
+ */