aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-06-18 22:19:17 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-06-18 22:19:17 +0200
commitfdbb6dbe1d394dfae5a0d9c6d1c550c07678bf16 (patch)
treeacbc13056152f4e770e9f8f5a93a66c597b0f7e6
parentc290ad8ed9bce2634231af82b62e1589ff4b0e57 (diff)
parent05e59dea673e07ab9a5ef98946d57857bf335c26 (diff)
downloadsparse-fdbb6dbe1d394dfae5a0d9c6d1c550c07678bf16.tar.gz
Merge branch 'genmacro'
* support for builtin macros with arguments * support for __has_feature() & __has_extension()
-rw-r--r--ident-list.h6
-rw-r--r--lib.c2
-rw-r--r--pre-process.c180
-rw-r--r--symbol.h4
-rw-r--r--validation/preprocessor/has-feature.c20
5 files changed, 151 insertions, 61 deletions
diff --git a/ident-list.h b/ident-list.h
index 75740b9d..8049b694 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -59,8 +59,10 @@ IDENT_RESERVED(__label__);
* sparse. */
IDENT(defined);
IDENT(once);
-IDENT(__has_attribute);
-IDENT(__has_builtin);
+IDENT(c_alignas);
+IDENT(c_alignof);
+IDENT(c_generic_selections);
+IDENT(c_static_assert);
__IDENT(pragma_ident, "__pragma__", 0);
__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0);
__IDENT(__func___ident, "__func__", 0);
diff --git a/lib.c b/lib.c
index 951d400e..88bb3109 100644
--- a/lib.c
+++ b/lib.c
@@ -1452,8 +1452,6 @@ static void create_builtin_stream(void)
add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
- add_pre_buffer("#define __has_builtin(x) 0\n");
- add_pre_buffer("#define __has_attribute(x) 0\n");
add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
diff --git a/pre-process.c b/pre-process.c
index e6becf23..38167802 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -160,18 +160,6 @@ static void replace_with_defined(struct token *token)
replace_with_bool(token, token_defined(token));
}
-static void replace_with_has_builtin(struct token *token)
-{
- struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
- replace_with_bool(token, sym && sym->builtin);
-}
-
-static void replace_with_has_attribute(struct token *token)
-{
- struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
- replace_with_bool(token, sym && sym->op && sym->op->attribute);
-}
-
static void expand_line(struct token *token)
{
replace_with_integer(token, token->pos.line);
@@ -229,8 +217,8 @@ static int expand_one_symbol(struct token **list)
sym = lookup_macro(token->ident);
if (!sym)
return 1;
- if (sym->expander) {
- sym->expander(token);
+ if (sym->expand_simple) {
+ sym->expand_simple(token);
return 1;
} else {
int rc;
@@ -777,6 +765,9 @@ static int expand(struct token **list, struct symbol *sym)
expand_arguments(nargs, args);
}
+ if (sym->expand)
+ return sym->expand(token, args) ? 0 : 1;
+
expanding->tainted = 1;
last = token->next;
@@ -1606,14 +1597,6 @@ static int expression_value(struct token **where)
state = 1;
beginning = list;
break;
- } else if (p->ident == &__has_builtin_ident) {
- state = 4;
- beginning = list;
- break;
- } else if (p->ident == &__has_attribute_ident) {
- state = 6;
- beginning = list;
- break;
}
if (!expand_one_symbol(list))
continue;
@@ -1644,38 +1627,6 @@ static int expression_value(struct token **where)
sparse_error(p->pos, "missing ')' after \"defined\"");
*list = p->next;
continue;
-
- // __has_builtin(x) or __has_attribute(x)
- case 4: case 6:
- if (match_op(p, '(')) {
- state++;
- } else {
- sparse_error(p->pos, "missing '(' after \"__has_%s\"",
- state == 4 ? "builtin" : "attribute");
- state = 0;
- }
- *beginning = p;
- break;
- case 5: case 7:
- if (token_type(p) != TOKEN_IDENT) {
- sparse_error(p->pos, "identifier expected");
- state = 0;
- break;
- }
- if (!match_op(p->next, ')'))
- sparse_error(p->pos, "missing ')' after \"__has_%s\"",
- state == 5 ? "builtin" : "attribute");
- if (state == 5)
- replace_with_has_builtin(p);
- else
- replace_with_has_attribute(p);
- state = 8;
- *beginning = p;
- break;
- case 8:
- state = 0;
- *list = p->next;
- continue;
}
list = &p->next;
}
@@ -2000,6 +1951,116 @@ static int handle_nondirective(struct stream *stream, struct token **line, struc
return 1;
}
+static bool expand_has_attribute(struct token *token, struct arg *args)
+{
+ struct token *arg = args[0].expanded;
+ struct symbol *sym;
+
+ if (token_type(arg) != TOKEN_IDENT) {
+ sparse_error(arg->pos, "identifier expected");
+ return false;
+ }
+
+ sym = lookup_symbol(arg->ident, NS_KEYWORD);
+ replace_with_bool(token, sym && sym->op && sym->op->attribute);
+ return true;
+}
+
+static bool expand_has_builtin(struct token *token, struct arg *args)
+{
+ struct token *arg = args[0].expanded;
+ struct symbol *sym;
+
+ if (token_type(arg) != TOKEN_IDENT) {
+ sparse_error(arg->pos, "identifier expected");
+ return false;
+ }
+
+ sym = lookup_symbol(arg->ident, NS_SYMBOL);
+ replace_with_bool(token, sym && sym->builtin);
+ return true;
+}
+
+static bool expand_has_extension(struct token *token, struct arg *args)
+{
+ struct token *arg = args[0].expanded;
+ struct ident *ident;
+ bool val = false;
+
+ if (token_type(arg) != TOKEN_IDENT) {
+ sparse_error(arg->pos, "identifier expected");
+ return false;
+ }
+
+ ident = arg->ident;
+ if (ident == &c_alignas_ident)
+ val = true;
+ else if (ident == &c_alignof_ident)
+ val = true;
+ else if (ident == &c_generic_selections_ident)
+ val = true;
+ else if (ident == &c_static_assert_ident)
+ val = true;
+
+ replace_with_bool(token, val);
+ return 1;
+}
+
+static bool expand_has_feature(struct token *token, struct arg *args)
+{
+ struct token *arg = args[0].expanded;
+ struct ident *ident;
+ bool val = false;
+
+ if (token_type(arg) != TOKEN_IDENT) {
+ sparse_error(arg->pos, "identifier expected");
+ return false;
+ }
+
+ ident = arg->ident;
+ if (standard >= STANDARD_C11) {
+ if (ident == &c_alignas_ident)
+ val = true;
+ else if (ident == &c_alignof_ident)
+ val = true;
+ else if (ident == &c_generic_selections_ident)
+ val = true;
+ else if (ident == &c_static_assert_ident)
+ val = true;
+ }
+
+ replace_with_bool(token, val);
+ return 1;
+}
+
+static void create_arglist(struct symbol *sym, int count)
+{
+ struct token *token;
+ struct token **next;
+
+ if (!count)
+ return;
+
+ token = __alloc_token(0);
+ token_type(token) = TOKEN_ARG_COUNT;
+ token->count.normal = count;
+ sym->arglist = token;
+ next = &token->next;
+
+ while (count--) {
+ struct token *id, *uses;
+ id = __alloc_token(0);
+ token_type(id) = TOKEN_IDENT;
+ uses = __alloc_token(0);
+ token_type(uses) = TOKEN_ARG_COUNT;
+ uses->count.normal = 1;
+
+ *next = id;
+ id->next = uses;
+ next = &uses->next;
+ }
+ *next = &eof_token_entry;
+}
static void init_preprocessor(void)
{
@@ -2040,7 +2101,8 @@ static void init_preprocessor(void)
};
static struct {
const char *name;
- void (*expander)(struct token *);
+ void (*expand_simple)(struct token *);
+ bool (*expand)(struct token *, struct arg *args);
} dynamic[] = {
{ "__LINE__", expand_line },
{ "__FILE__", expand_file },
@@ -2049,6 +2111,10 @@ static void init_preprocessor(void)
{ "__TIME__", expand_time },
{ "__COUNTER__", expand_counter },
{ "__INCLUDE_LEVEL__", expand_include_level },
+ { "__has_attribute", NULL, expand_has_attribute },
+ { "__has_builtin", NULL, expand_has_builtin },
+ { "__has_extension", NULL, expand_has_extension },
+ { "__has_feature", NULL, expand_has_feature },
};
for (i = 0; i < ARRAY_SIZE(normal); i++) {
@@ -2066,7 +2132,9 @@ static void init_preprocessor(void)
for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
struct symbol *sym;
sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
- sym->expander = dynamic[i].expander;
+ sym->expand_simple = dynamic[i].expand_simple;
+ if ((sym->expand = dynamic[i].expand) != NULL)
+ create_arglist(sym, 1);
}
counter_macro = 0;
diff --git a/symbol.h b/symbol.h
index 0e642df0..67464d65 100644
--- a/symbol.h
+++ b/symbol.h
@@ -114,6 +114,7 @@ struct decl_state {
struct pseudo;
struct entrypoint;
+struct arg;
struct symbol_op {
enum keyword type;
@@ -160,7 +161,8 @@ struct symbol {
struct token *expansion;
struct token *arglist;
struct scope *used_in;
- void (*expander)(struct token *);
+ void (*expand_simple)(struct token *);
+ bool (*expand)(struct token *, struct arg *args);
};
struct /* NS_PREPROCESSOR */ {
int (*handler)(struct stream *, struct token **, struct token *);
diff --git a/validation/preprocessor/has-feature.c b/validation/preprocessor/has-feature.c
new file mode 100644
index 00000000..e0f2e7f6
--- /dev/null
+++ b/validation/preprocessor/has-feature.c
@@ -0,0 +1,20 @@
+#ifndef __has_feature
+__has_feature()??? Quesako?
+#define __has_feature(x) 0
+#else
+"has __has_feature(), yeah!"
+#endif
+
+#if __has_feature(not_a_feature)
+#error "not a feature!"
+#endif
+
+/*
+ * check-name: has-feature
+ * check-command: sparse -E $file
+ *
+ * check-output-start
+
+"has __has_feature(), yeah!"
+ * check-output-end
+ */