diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-06-18 22:19:17 +0200 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-06-18 22:19:17 +0200 |
commit | fdbb6dbe1d394dfae5a0d9c6d1c550c07678bf16 (patch) | |
tree | acbc13056152f4e770e9f8f5a93a66c597b0f7e6 | |
parent | c290ad8ed9bce2634231af82b62e1589ff4b0e57 (diff) | |
parent | 05e59dea673e07ab9a5ef98946d57857bf335c26 (diff) | |
download | sparse-fdbb6dbe1d394dfae5a0d9c6d1c550c07678bf16.tar.gz |
Merge branch 'genmacro'
* support for builtin macros with arguments
* support for __has_feature() & __has_extension()
-rw-r--r-- | ident-list.h | 6 | ||||
-rw-r--r-- | lib.c | 2 | ||||
-rw-r--r-- | pre-process.c | 180 | ||||
-rw-r--r-- | symbol.h | 4 | ||||
-rw-r--r-- | validation/preprocessor/has-feature.c | 20 |
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); @@ -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; @@ -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 + */ |