summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-11-29 17:54:26 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-12-14 13:57:56 +0100
commit137813ac795cd6b9f987afea7aec59100c3d311e (patch)
tree8e4f036002813aad2078e26457dadca09a686bba
parent6f9b33b07bb8e82d410bd74b0389a0ca391bde7e (diff)
downloadsparse-137813ac795cd6b9f987afea7aec59100c3d311e.tar.gz
teach sparse about asm inline
GCC's trunk now allows to specifiy 'inline' with asm statements. This feature has been asked by kernel devs and will most probably by used for the kernel. So, teach sparse about this syntax too. Note: for sparse, there is no semantic associated to this inline because sparse doesn't make any size-based inlining decisions. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--parse.c34
-rw-r--r--symbol.h2
-rw-r--r--validation/asm-inline.c52
3 files changed, 81 insertions, 7 deletions
diff --git a/parse.c b/parse.c
index a12104f5..4784ff57 100644
--- a/parse.c
+++ b/parse.c
@@ -118,6 +118,23 @@ enum {
SNone = 0, STypedef, SAuto, SRegister, SExtern, SStatic, SForced, SMax,
};
+static void asm_modifier(struct token *token, unsigned long *mods, unsigned long mod)
+{
+ if (*mods & mod)
+ warning(token->pos, "duplicated asm modifier");
+ *mods |= mod;
+}
+
+static void asm_modifier_volatile(struct token *token, unsigned long *mods)
+{
+ asm_modifier(token, mods, MOD_VOLATILE);
+}
+
+static void asm_modifier_inline(struct token *token, unsigned long *mods)
+{
+ asm_modifier(token, mods, MOD_INLINE);
+}
+
static struct symbol_op typedef_op = {
.type = KW_MODIFIER,
.declarator = typedef_specifier,
@@ -126,6 +143,7 @@ static struct symbol_op typedef_op = {
static struct symbol_op inline_op = {
.type = KW_MODIFIER,
.declarator = inline_specifier,
+ .asm_modifier = asm_modifier_inline,
};
static declarator_t noreturn_specifier;
@@ -173,6 +191,7 @@ static struct symbol_op const_op = {
static struct symbol_op volatile_op = {
.type = KW_QUALIFIER,
.declarator = volatile_qualifier,
+ .asm_modifier = asm_modifier_volatile,
};
static struct symbol_op restrict_op = {
@@ -2069,15 +2088,16 @@ static struct token *parse_asm_labels(struct token *token, struct statement *stm
static struct token *parse_asm_statement(struct token *token, struct statement *stmt)
{
- int is_goto = 0;
+ unsigned long mods = 0;
token = token->next;
stmt->type = STMT_ASM;
- if (match_idents(token, &__volatile___ident, &__volatile_ident, &volatile_ident, NULL)) {
- token = token->next;
- }
- if (token_type(token) == TOKEN_IDENT && token->ident == &goto_ident) {
- is_goto = 1;
+ while (token_type(token) == TOKEN_IDENT) {
+ struct symbol *s = lookup_keyword(token->ident, NS_TYPEDEF);
+ if (s && s->op && s->op->asm_modifier)
+ s->op->asm_modifier(token, &mods);
+ else if (token->ident == &goto_ident)
+ asm_modifier(token, &mods, MOD_ASM_GOTO);
token = token->next;
}
token = expect(token, '(', "after asm");
@@ -2088,7 +2108,7 @@ static struct token *parse_asm_statement(struct token *token, struct statement *
token = parse_asm_operands(token, stmt, &stmt->asm_inputs);
if (match_op(token, ':'))
token = parse_asm_clobbers(token, stmt, &stmt->asm_clobbers);
- if (is_goto && match_op(token, ':'))
+ if (match_op(token, ':') && (mods & MOD_ASM_GOTO))
token = parse_asm_labels(token, stmt, &stmt->asm_labels);
token = expect(token, ')', "after asm");
return expect(token, ';', "at end of asm-statement");
diff --git a/symbol.h b/symbol.h
index 87d3ce53..d4c4d120 100644
--- a/symbol.h
+++ b/symbol.h
@@ -124,6 +124,7 @@ struct symbol_op {
struct token *(*toplevel)(struct token *token, struct symbol_list **list);
struct token *(*attribute)(struct token *token, struct symbol *attr, struct decl_state *ctx);
struct symbol *(*to_mode)(struct symbol *);
+ void (*asm_modifier)(struct token *token, unsigned long *mods);
int test, set, class;
};
@@ -207,6 +208,7 @@ struct symbol {
#define MOD_EXTERN 0x00000008
#define MOD_TOPLEVEL 0x00000010 // scoping..
#define MOD_TLS 0x00000020
+#define MOD_ASM_GOTO MOD_TLS // never used together
#define MOD_INLINE 0x00000040
#define MOD_ASSIGNED 0x00000080
diff --git a/validation/asm-inline.c b/validation/asm-inline.c
new file mode 100644
index 00000000..186286b3
--- /dev/null
+++ b/validation/asm-inline.c
@@ -0,0 +1,52 @@
+static void foo(void)
+{
+ asm("");
+ asm volatile ("v");
+ asm inline ("i");
+ asm volatile inline ("vi");
+ asm inline volatile ("iv");
+
+ asm goto ("g" :::: label);
+ asm volatile goto ("vg" :::: label);
+ asm inline goto ("ig" :::: label);
+ asm volatile inline goto ("vig" :::: label);
+ asm inline volatile goto ("ivg" :::: label);
+
+ asm goto volatile ("gv" :::: label);
+ asm goto inline ("gi" :::: label);
+ asm goto volatile inline ("gvi" :::: label);
+ asm goto inline volatile ("giv" :::: label);
+ asm volatile goto inline ("vgi" :::: label);
+ asm inline goto volatile ("giv" :::: label);
+
+ // warn on duplicates
+ asm volatile volatile ("vv");
+ asm inline inline ("ii");
+ asm goto goto ("gg" :::: label);
+
+ asm inline volatile inline ("ivi");
+ asm inline goto inline ("igi" :::: label);
+ asm goto inline goto ("gig" :::: label);
+ asm goto volatile goto ("gvg" :::: label);
+ asm volatile inline volatile ("viv");
+ asm volatile goto volatile ("vgv" :::: label);
+
+label:
+ ;
+}
+
+/*
+ * check-name: asm-inline
+ *
+ * check-error-start
+asm-inline.c:23:22: warning: duplicated asm modifier
+asm-inline.c:24:20: warning: duplicated asm modifier
+asm-inline.c:25:18: warning: duplicated asm modifier
+asm-inline.c:27:29: warning: duplicated asm modifier
+asm-inline.c:28:25: warning: duplicated asm modifier
+asm-inline.c:29:25: warning: duplicated asm modifier
+asm-inline.c:30:27: warning: duplicated asm modifier
+asm-inline.c:31:29: warning: duplicated asm modifier
+asm-inline.c:32:27: warning: duplicated asm modifier
+ * check-error-end
+ */