Print this page
11972 resync smatch
*** 47,56 ****
--- 47,57 ----
#include "scope.h"
static struct ident_list *macros; // only needed for -dD
static int false_nesting = 0;
static int counter_macro = 0; // __COUNTER__ expansion
+ static int include_level = 0;
#define INCLUDEPATHS 300
const char *includepath[INCLUDEPATHS+1] = {
"",
"/usr/include",
*** 145,197 ****
sparse_error(token->pos, "expected preprocessor identifier");
return 0;
}
! static void replace_with_defined(struct token *token)
{
static const char *string[] = { "0", "1" };
- int defined = token_defined(token);
token_type(token) = TOKEN_NUMBER;
! token->number = string[defined];
}
! static int expand_one_symbol(struct token **list)
{
! struct token *token = *list;
! struct symbol *sym;
! static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
! static time_t t = 0;
! if (token->pos.noexpand)
! return 1;
! sym = lookup_macro(token->ident);
! if (sym) {
! store_macro_pos(token);
! sym->used_in = file_scope;
! return expand(list, sym);
! }
! if (token->ident == &__LINE___ident) {
replace_with_integer(token, token->pos.line);
! } else if (token->ident == &__FILE___ident) {
replace_with_string(token, stream_name(token->pos.stream));
! } else if (token->ident == &__DATE___ident) {
if (!t)
time(&t);
strftime(buffer, 12, "%b %e %Y", localtime(&t));
replace_with_string(token, buffer);
! } else if (token->ident == &__TIME___ident) {
if (!t)
time(&t);
strftime(buffer, 9, "%T", localtime(&t));
replace_with_string(token, buffer);
! } else if (token->ident == &__COUNTER___ident) {
replace_with_integer(token, counter_macro++);
! }
return 1;
}
static inline struct token *scan_next(struct token **where)
{
struct token *token = *where;
--- 146,245 ----
sparse_error(token->pos, "expected preprocessor identifier");
return 0;
}
! static void replace_with_bool(struct token *token, bool val)
{
static const char *string[] = { "0", "1" };
token_type(token) = TOKEN_NUMBER;
! token->number = string[val];
}
! 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);
! }
!
! static void expand_file(struct token *token)
! {
replace_with_string(token, stream_name(token->pos.stream));
! }
!
! static void expand_basefile(struct token *token)
! {
! replace_with_string(token, base_filename);
! }
!
! static time_t t = 0;
! static void expand_date(struct token *token)
! {
! static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
!
if (!t)
time(&t);
strftime(buffer, 12, "%b %e %Y", localtime(&t));
replace_with_string(token, buffer);
! }
!
! static void expand_time(struct token *token)
! {
! static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
!
if (!t)
time(&t);
strftime(buffer, 9, "%T", localtime(&t));
replace_with_string(token, buffer);
! }
!
! static void expand_counter(struct token *token)
! {
replace_with_integer(token, counter_macro++);
! }
!
! static void expand_include_level(struct token *token)
! {
! replace_with_integer(token, include_level - 1);
! }
!
! static int expand_one_symbol(struct token **list)
! {
! struct token *token = *list;
! struct symbol *sym;
!
! if (token->pos.noexpand)
return 1;
+
+ sym = lookup_macro(token->ident);
+ if (!sym)
+ return 1;
+ store_macro_pos(token);
+ if (sym->expander) {
+ sym->expander(token);
+ return 1;
+ } else {
+ sym->used_in = file_scope;
+ return expand(list, sym);
+ }
}
static inline struct token *scan_next(struct token **where)
{
struct token *token = *where;
*** 512,528 ****
case TOKEN_IDENT:
left->ident = built_in_ident(buffer);
left->pos.noexpand = 0;
return 1;
! case TOKEN_NUMBER: {
! char *number = __alloc_bytes(strlen(buffer) + 1);
! memcpy(number, buffer, strlen(buffer) + 1);
token_type(left) = TOKEN_NUMBER; /* could be . + num */
! left->number = number;
return 1;
- }
case TOKEN_SPECIAL:
if (buffer[2] && buffer[3])
break;
for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) {
--- 560,573 ----
case TOKEN_IDENT:
left->ident = built_in_ident(buffer);
left->pos.noexpand = 0;
return 1;
! case TOKEN_NUMBER:
token_type(left) = TOKEN_NUMBER; /* could be . + num */
! left->number = xstrdup(buffer);
return 1;
case TOKEN_SPECIAL:
if (buffer[2] && buffer[3])
break;
for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) {
*** 849,858 ****
--- 894,907 ----
stream->path = path;
}
includepath[0] = path;
}
+ #ifndef PATH_MAX
+ #define PATH_MAX 4096 // for Hurd where it's not defined
+ #endif
+
static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
{
int fd;
int plen = strlen(path);
static char fullname[PATH_MAX];
*** 865,876 ****
memcpy(fullname+plen, filename, flen);
if (already_tokenized(fullname))
return 1;
fd = open(fullname, O_RDONLY);
if (fd >= 0) {
! char * streamname = __alloc_bytes(plen + flen);
! memcpy(streamname, fullname, plen + flen);
*where = tokenize(streamname, fd, *where, next_path);
close(fd);
return 1;
}
return 0;
--- 914,924 ----
memcpy(fullname+plen, filename, flen);
if (already_tokenized(fullname))
return 1;
fd = open(fullname, O_RDONLY);
if (fd >= 0) {
! char *streamname = xmemdup(fullname, plen + flen);
*where = tokenize(streamname, fd, *where, next_path);
close(fd);
return 1;
}
return 0;
*** 910,926 ****
dp = opendir(".");
if (!dp)
return NULL;
if (!getcwd(cwd, sizeof(cwd)))
! return NULL;
while ((entry = readdir(dp))) {
lstat(entry->d_name, &statbuf);
if (strcmp(entry->d_name, look_for) == 0) {
snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
return buf;
}
if (S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
--- 958,975 ----
dp = opendir(".");
if (!dp)
return NULL;
if (!getcwd(cwd, sizeof(cwd)))
! goto close;
while ((entry = readdir(dp))) {
lstat(entry->d_name, &statbuf);
if (strcmp(entry->d_name, look_for) == 0) {
snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
+ closedir(dp);
return buf;
}
if (S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
*** 930,943 ****
continue;
chdir(entry->d_name);
ret = find_include("", look_for);
chdir("..");
! if (ret)
return ret;
}
}
closedir(dp);
return NULL;
}
--- 979,995 ----
continue;
chdir(entry->d_name);
ret = find_include("", look_for);
chdir("..");
! if (ret) {
! closedir(dp);
return ret;
}
}
+ }
+ close:
closedir(dp);
return NULL;
}
*** 980,991 ****
--- 1032,1048 ----
{
char cwd[PATH_MAX];
char dir_part[PATH_MAX];
const char *file_part;
const char *include_name;
+ static int cnt;
int len;
+ /* Avoid guessing includes recursively. */
+ if (cnt++ > 1000)
+ return;
+
if (!filename || filename[0] == '\0')
return;
file_part = filename;
while ((filename = strchr(filename, '/'))) {
*** 1418,1461 ****
Earg:
sparse_error(token->pos, "too many instances of argument in body");
return NULL;
}
! static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
{
- struct token *arglist, *expansion;
- struct token *left = token->next;
struct symbol *sym;
! struct ident *name;
! int ret;
- if (token_type(left) != TOKEN_IDENT) {
- sparse_error(token->pos, "expected identifier to 'define'");
- return 1;
- }
-
- name = left->ident;
-
- arglist = NULL;
- expansion = left->next;
- if (!expansion->pos.whitespace) {
- if (match_op(expansion, '(')) {
- arglist = expansion;
- expansion = parse_arguments(expansion);
- if (!expansion)
- return 1;
- } else if (!eof_token(expansion)) {
- warning(expansion->pos,
- "no whitespace before object-like macro body");
- }
- }
-
expansion = parse_expansion(expansion, arglist, name);
if (!expansion)
return 1;
- ret = 1;
sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
if (sym) {
int clean;
if (attr < sym->attr)
--- 1475,1494 ----
Earg:
sparse_error(token->pos, "too many instances of argument in body");
return NULL;
}
! static int do_define(struct position pos, struct token *token, struct ident *name,
! struct token *arglist, struct token *expansion, int attr)
{
struct symbol *sym;
! int ret = 1;
expansion = parse_expansion(expansion, arglist, name);
if (!expansion)
return 1;
sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
if (sym) {
int clean;
if (attr < sym->attr)
*** 1466,1503 ****
if (token_list_different(sym->expansion, expansion) ||
token_list_different(sym->arglist, arglist)) {
ret = 0;
if ((clean && attr == SYM_ATTR_NORMAL)
|| sym->used_in == file_scope) {
! warning(left->pos, "preprocessor token %.*s redefined",
name->len, name->name);
info(sym->pos, "this was the original definition");
}
} else if (clean)
goto out;
}
if (!sym || sym->scope != file_scope) {
! sym = alloc_symbol(left->pos, SYM_NODE);
bind_symbol(sym, name, NS_MACRO);
add_ident(¯os, name);
ret = 0;
}
if (!ret) {
sym->expansion = expansion;
sym->arglist = arglist;
! __free_token(token); /* Free the "define" token, but not the rest of the line */
}
sym->namespace = NS_MACRO;
sym->used_in = NULL;
sym->attr = attr;
out:
return ret;
}
static int handle_define(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
}
--- 1499,1605 ----
if (token_list_different(sym->expansion, expansion) ||
token_list_different(sym->arglist, arglist)) {
ret = 0;
if ((clean && attr == SYM_ATTR_NORMAL)
|| sym->used_in == file_scope) {
! warning(pos, "preprocessor token %.*s redefined",
name->len, name->name);
info(sym->pos, "this was the original definition");
}
} else if (clean)
goto out;
}
if (!sym || sym->scope != file_scope) {
! sym = alloc_symbol(pos, SYM_NODE);
bind_symbol(sym, name, NS_MACRO);
add_ident(¯os, name);
ret = 0;
}
if (!ret) {
sym->expansion = expansion;
sym->arglist = arglist;
! if (token) /* Free the "define" token, but not the rest of the line */
! __free_token(token);
}
sym->namespace = NS_MACRO;
sym->used_in = NULL;
sym->attr = attr;
out:
return ret;
}
+ ///
+ // predefine a macro with a printf-formatted value
+ // @name: the name of the macro
+ // @weak: 0/1 for a normal or a weak define
+ // @fmt: the printf format followed by it's arguments.
+ //
+ // The type of the value is automatically infered:
+ // TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
+ // If @fmt is null or empty, the macro is defined with an empty definition.
+ void predefine(const char *name, int weak, const char *fmt, ...)
+ {
+ struct ident *ident = built_in_ident(name);
+ struct token *value = &eof_token_entry;
+ int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
+
+ if (fmt && fmt[0]) {
+ static char buf[256];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ value = __alloc_token(0);
+ if (isdigit(buf[0])) {
+ token_type(value) = TOKEN_NUMBER;
+ value->number = xstrdup(buf);
+ } else {
+ token_type(value) = TOKEN_IDENT;
+ value->ident = built_in_ident(buf);
+ }
+ value->pos.whitespace = 1;
+ value->next = &eof_token_entry;
+ }
+
+ do_define(value->pos, NULL, ident, NULL, value, attr);
+ }
+
+ static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+ {
+ struct token *arglist, *expansion;
+ struct token *left = token->next;
+ struct ident *name;
+
+ if (token_type(left) != TOKEN_IDENT) {
+ sparse_error(token->pos, "expected identifier to 'define'");
+ return 1;
+ }
+
+ name = left->ident;
+
+ arglist = NULL;
+ expansion = left->next;
+ if (!expansion->pos.whitespace) {
+ if (match_op(expansion, '(')) {
+ arglist = expansion;
+ expansion = parse_arguments(expansion);
+ if (!expansion)
+ return 1;
+ } else if (!eof_token(expansion)) {
+ warning(expansion->pos,
+ "no whitespace before object-like macro body");
+ }
+ }
+
+ return do_define(left->pos, token, name, arglist, expansion, attr);
+ }
+
static int handle_define(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
}
*** 1550,1566 ****
static int handle_strong_undef(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
}
! static int preprocessor_if(struct stream *stream, struct token *token, int true)
{
token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
free_preprocessor_line(token->next);
token->next = stream->top_if;
stream->top_if = token;
! if (false_nesting || true != 1)
false_nesting++;
return 0;
}
static int handle_ifdef(struct stream *stream, struct token **line, struct token *token)
--- 1652,1668 ----
static int handle_strong_undef(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
}
! static int preprocessor_if(struct stream *stream, struct token *token, int cond)
{
token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
free_preprocessor_line(token->next);
token->next = stream->top_if;
stream->top_if = token;
! if (false_nesting || cond != 1)
false_nesting++;
return 0;
}
static int handle_ifdef(struct stream *stream, struct token **line, struct token *token)
*** 1624,1633 ****
--- 1726,1743 ----
break;
if (p->ident == &defined_ident) {
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;
if (token_type(p) != TOKEN_IDENT)
break;
*** 1654,1664 ****
--- 1764,1806 ----
state = 0;
if (!match_op(p, ')'))
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;
}
p = constant_expression(*where, &expr);
if (!eof_token(p))
*** 1967,1979 ****
static int handle_line(struct stream *stream, struct token **line, struct token *token)
{
return 1;
}
- /*
- * Ignore "#ident".
- */
static int handle_ident(struct stream *stream, struct token **line, struct token *token)
{
return 1;
}
--- 2109,2118 ----
*** 2019,2028 ****
--- 2158,2179 ----
{ "else", handle_else },
{ "endif", handle_endif },
{ "if", handle_if },
{ "elif", handle_elif },
};
+ static struct {
+ const char *name;
+ void (*expander)(struct token *);
+ } dynamic[] = {
+ { "__LINE__", expand_line },
+ { "__FILE__", expand_file },
+ { "__BASE_FILE__", expand_basefile },
+ { "__DATE__", expand_date },
+ { "__TIME__", expand_time },
+ { "__COUNTER__", expand_counter },
+ { "__INCLUDE_LEVEL__", expand_include_level },
+ };
for (i = 0; i < ARRAY_SIZE(normal); i++) {
struct symbol *sym;
sym = create_symbol(stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
sym->handler = normal[i].handler;
*** 2032,2041 ****
--- 2183,2197 ----
struct symbol *sym;
sym = create_symbol(stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
sym->handler = special[i].handler;
sym->normal = 0;
}
+ 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;
+ }
counter_macro = 0;
}
static void handle_preprocessor_line(struct stream *stream, struct token **line, struct token *start)
*** 2113,2125 ****
--- 2269,2283 ----
false_nesting = 0;
}
if (!stream->dirty)
stream->constant = CONSTANT_FILE_YES;
*list = next->next;
+ include_level--;
continue;
case TOKEN_STREAMBEGIN:
*list = next->next;
+ include_level++;
continue;
default:
dirty_stream(stream);
if (false_nesting) {
*** 2177,2186 ****
--- 2335,2350 ----
preprocessing = 0;
return token;
}
+ static int is_VA_ARGS_token(struct token *token)
+ {
+ return (token_type(token) == TOKEN_IDENT) &&
+ (token->ident == &__VA_ARGS___ident);
+ }
+
static void dump_macro(struct symbol *sym)
{
int nargs = sym->arglist ? sym->arglist->count.normal : 0;
struct token *args[nargs];
struct token *token;
*** 2192,2222 ****
int narg = 0;
putchar('(');
for (; !eof_token(token); token = token->next) {
if (token_type(token) == TOKEN_ARG_COUNT)
continue;
printf("%s%s", sep, show_token(token));
args[narg++] = token;
! sep = ", ";
}
putchar(')');
}
- putchar(' ');
token = sym->expansion;
! while (!eof_token(token)) {
struct token *next = token->next;
switch (token_type(token)) {
! case TOKEN_UNTAINT:
break;
case TOKEN_MACRO_ARGUMENT:
token = args[token->argnum];
/* fall-through */
default:
printf("%s", show_token(token));
- if (next->pos.whitespace)
- putchar(' ');
}
token = next;
}
putchar('\n');
}
--- 2356,2393 ----
int narg = 0;
putchar('(');
for (; !eof_token(token); token = token->next) {
if (token_type(token) == TOKEN_ARG_COUNT)
continue;
+ if (is_VA_ARGS_token(token))
+ printf("%s...", sep);
+ else
printf("%s%s", sep, show_token(token));
args[narg++] = token;
! sep = ",";
}
putchar(')');
}
token = sym->expansion;
! while (token_type(token) != TOKEN_UNTAINT) {
struct token *next = token->next;
+ if (token->pos.whitespace)
+ putchar(' ');
switch (token_type(token)) {
! case TOKEN_CONCAT:
! printf("##");
break;
+ case TOKEN_STR_ARGUMENT:
+ printf("#");
+ /* fall-through */
+ case TOKEN_QUOTED_ARGUMENT:
case TOKEN_MACRO_ARGUMENT:
token = args[token->argnum];
/* fall-through */
default:
printf("%s", show_token(token));
}
token = next;
}
putchar('\n');
}