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(&macros, 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(&macros, 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'); }