diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-06-08 03:38:29 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-06-08 18:55:02 +0200 |
| commit | a6e80f36afca7b7f6eeaf557cdbd1effca5cc810 (patch) | |
| tree | e272207624986109e767bd2790c921adcf240f16 /pre-process.c | |
| parent | 35b50cdb51b6c32262103672277135cb0b5311e6 (diff) | |
| download | sparse-dev-a6e80f36afca7b7f6eeaf557cdbd1effca5cc810.tar.gz | |
builtin: add support for __has_builtin()
Sparse has support for a subset of GCC's large collection of builtin
functions. As for GCC, it's not easy to know which builtins are
supported in which versions.
clang has a good solution to this problem: it adds the checking macro
__has_builtin(<name>) which evaluates to 1 if <name> is a builtin
function supported by the compiler and 0 otherwise.
It can be used like:
#if __has_builtin(__builtin_clz)
#define clz(x) __builtin_clz(x)
#else
...
#endif
It's possible or probable that GCC will have this soon too:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970
Add support for this __has_builtin() macro by extending
the evaluation of preprocessor expressions very much like
it is done to support defined().
Note: Some function-like builtin features, like __builtin_offset(), are
considered as a kind of keyword/operator and processed as such.
These are *not* considered as builtins by __has_builtin().
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'pre-process.c')
| -rw-r--r-- | pre-process.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/pre-process.c b/pre-process.c index b44231fd..547ce092 100644 --- a/pre-process.c +++ b/pre-process.c @@ -159,6 +159,12 @@ 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 expand_line(struct token *token) { replace_with_integer(token, token->pos.line); @@ -1541,6 +1547,10 @@ static int expression_value(struct token **where) state = 1; beginning = list; break; + } else if (p->ident == &__has_builtin_ident) { + state = 4; + beginning = list; + break; } if (!expand_one_symbol(list)) continue; @@ -1571,6 +1581,33 @@ static int expression_value(struct token **where) sparse_error(p->pos, "missing ')' after \"defined\""); *list = p->next; continue; + + // __has_builtin(xyz) + case 4: + if (match_op(p, '(')) { + state = 5; + } else { + sparse_error(p->pos, "missing '(' after \"__has_builtin\""); + state = 0; + } + *beginning = p; + break; + case 5: + 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_builtin\""); + state = 6; + replace_with_has_builtin(p); + *beginning = p; + break; + case 6: + state = 0; + *list = p->next; + continue; } list = &p->next; } |
