[PATCH 06/21] try_arg(): don't use arglist for argument name lookups
Al Viro <[email protected]> Mon, 16 Mar 2026 07:04:00 +0000
| Newsgroups | org.kernel.vger.linux-sparse |
|---|---|
| Message-ID | <[email protected]> |
Just store them into a global array and search there. That allows to get rid of mangling ... in the arglist along with the is_VA_ARGS_token() kludge. For now we still need to access the arglist in try_arg(), but that's going away as soon as we get rid of the use counters... Added a check for duplicate argument names, while we are at it - we didn't do that. Signed-off-by: Al Viro <[email protected]> --- pre-process.c | 90 ++++++++++++++-------------- validation/preprocessor/bad-args.c | 18 ++++++ validation/preprocessor/dump-macro.c | 9 +++ 3 files changed, 72 insertions(+), 45 deletions(-) create mode 100644 validation/preprocessor/bad-args.c create mode 100644 validation/preprocessor/dump-macro.c diff --git a/pre-process.c b/pre-process.c index 25990dfa..17ed7f85 100644 --- a/pre-process.c +++ b/pre-process.c @@ -1078,16 +1078,24 @@ static int token_list_different(struct token *list1, struct token *list2) } } +static struct ident *macro_arg_name[1024]; static int macro_nargs = 0; static int macro_vararg = -1; static bool macro_funclike = false; static bool macro_add_arg(struct position pos, struct ident *ident) { + for (int i = 0; i < macro_nargs; i++) { + if (ident == macro_arg_name[i]) + goto Edup_arg; + } if (macro_nargs == 1024) goto Eargs; - macro_nargs++; + macro_arg_name[macro_nargs++] = ident; return true; +Edup_arg: + sparse_error(pos, "duplicate macro parameter \"%s\"", show_ident(ident)); + return false; Eargs: sparse_error(pos, "too many arguments in macro definition"); return false; @@ -1157,8 +1165,6 @@ static struct token *parse_arguments(struct token *list) if (match_op(arg, SPECIAL_ELLIPSIS)) { next = arg->next; - token_type(arg) = TOKEN_IDENT; - arg->ident = &__VA_ARGS___ident; if (!match_op(next, ')')) goto Enotclosed; if (!macro_add_arg(arg->pos, &__VA_ARGS___ident)) @@ -1198,41 +1204,41 @@ Eva_args: static int try_arg(struct token *token, enum token_type type, struct token *arglist) { struct ident *ident = token->ident; - int nr; + int nr, n; if (!macro_funclike || token_type(token) != TOKEN_IDENT) return 0; - arglist = arglist->next; + for (nr = 0; nr < macro_nargs && macro_arg_name[nr] != ident; nr++) + ; - for (nr = 0; !eof_token(arglist); nr++, arglist = arglist->next->next) { - if (arglist->ident == ident) { - struct argcount *count = &arglist->next->count; - int n; + if (nr == macro_nargs) + return 0; - token->argnum = nr; - token_type(token) = type; - switch (type) { - case TOKEN_MACRO_ARGUMENT: - n = ++count->normal; - break; - case TOKEN_QUOTED_ARGUMENT: - n = ++count->quoted; - break; - default: - n = ++count->str; - } - if (n) - return nr == macro_vararg ? 2 : 1; - /* - * XXX - need saner handling of that - * (>= 1024 instances of argument) - */ - token_type(token) = TOKEN_ERROR; - return -1; - } + arglist = arglist->next; + for (int i = 0; i < nr; i++) + arglist = arglist->next->next; + + token->argnum = nr; + token_type(token) = type; + switch (type) { + case TOKEN_MACRO_ARGUMENT: + n = ++arglist->next->count.normal; + break; + case TOKEN_QUOTED_ARGUMENT: + n = ++arglist->next->count.quoted; + break; + default: + n = ++arglist->next->count.str; } - return 0; + if (n) + return nr == macro_vararg ? 2 : 1; + /* + * XXX - need saner handling of that + * (>= 1024 instances of argument) + */ + token_type(token) = TOKEN_ERROR; + return -1; } static struct token *handle_hash(struct token **p, struct token *arglist) @@ -2304,16 +2310,10 @@ struct token * preprocess(struct token *token) 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->fixed_args + sym->vararg; - struct token *args[nargs]; + struct ident *args[nargs]; struct token *token; printf("#define %s", show_ident(sym->ident)); @@ -2325,13 +2325,13 @@ static void dump_macro(struct symbol *sym) 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; + printf("%s%s", sep, show_token(token)); + if (token_type(token) == TOKEN_IDENT) + args[narg++] = token->ident; sep = ","; } + if (narg < nargs) + args[narg] = &__VA_ARGS___ident; putchar(')'); } @@ -2349,8 +2349,8 @@ static void dump_macro(struct symbol *sym) /* fall-through */ case TOKEN_QUOTED_ARGUMENT: case TOKEN_MACRO_ARGUMENT: - token = args[token->argnum]; - /* fall-through */ + printf("%s", show_ident(args[token->argnum])); + break; default: printf("%s", show_token(token)); } diff --git a/validation/preprocessor/bad-args.c b/validation/preprocessor/bad-args.c new file mode 100644 index 00000000..3dbb6f92 --- /dev/null +++ b/validation/preprocessor/bad-args.c @@ -0,0 +1,18 @@ +#define A(1) +#define B(__VA_ARGS__) +#define C(X,Y,X) +/* + * check-name: macro arguments validation + * check-command: sparse -E $file + * + * check-output-start + + + * check-output-end + * + * check-error-start +preprocessor/bad-args.c:1:11: error: "1" may not appear in macro parameter list +preprocessor/bad-args.c:2:11: error: __VA_ARGS__ can only appear in the expansion of a C99 variadic macro +preprocessor/bad-args.c:3:15: error: duplicate macro parameter "X" + * check-error-end + */ diff --git a/validation/preprocessor/dump-macro.c b/validation/preprocessor/dump-macro.c new file mode 100644 index 00000000..46d70b34 --- /dev/null +++ b/validation/preprocessor/dump-macro.c @@ -0,0 +1,9 @@ +#define A(X,Y,...) __VA_ARGS__,Y,X +/* + * check-name: -dM handling of varargs + * check-command: sparse -E -dM $file | tail -1 + * + * check-output-start +#define A(X,Y,...) __VA_ARGS__,Y,X + * check-output-end + */ -- 2.47.3