[PATCH] accept an empty attribute argument list
Dmitry Ilvokhin <[email protected]> Fri, 5 Jun 2026 11:30:45 +0000
| Newsgroups | org.kernel.vger.linux-sparse |
|---|---|
| Message-ID | <[email protected]> |
GCC and clang accept an empty argument list for attributes, e.g. __attribute__((nonnull())), and treat it the same as the bare __attribute__((nonnull)). sparse instead rejects it with "an expression is expected before ')'". ignore_attribute() and recover_unknown_attribute() consume the optional argument list with parens_expression(), which requires a non-empty expression, so an empty () is rejected. The bare form is fine because it takes no parentheses and skips that path. This turned up in the Linux kernel: the cleanup.h guard macros expand __nonnull_args() to __attribute__((__nonnull__())). https://lore.kernel.org/all/[email protected]/ Reported-by: Dan Carpenter <[email protected]> Signed-off-by: Dmitry Ilvokhin <[email protected]> --- parse.c | 17 +++++++++++++---- validation/attribute-nonnull-empty.c | 12 ++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 validation/attribute-nonnull-empty.c diff --git a/parse.c b/parse.c index 9389079e..3b380156 100644 --- a/parse.c +++ b/parse.c @@ -1106,8 +1106,13 @@ static struct token *autotype_specifier(struct token *token, struct symbol *sym, static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct decl_state *ctx) { struct expression *expr = NULL; - if (match_op(token, '(')) - token = parens_expression(token, &expr, "in attribute"); + if (match_op(token, '(')) { + /* Accept an empty argument list, e.g. __attribute__((nonnull())) */ + if (match_op(token->next, ')')) + token = token->next->next; + else + token = parens_expression(token, &expr, "in attribute"); + } return token; } @@ -1362,8 +1367,12 @@ static struct token *recover_unknown_attribute(struct token *token) if (Wunknown_attribute) warning(token->pos, "unknown attribute '%s'", show_ident(token->ident)); token = token->next; - if (match_op(token, '(')) - token = parens_expression(token, &expr, "in attribute"); + if (match_op(token, '(')) { + if (match_op(token->next, ')')) + token = token->next->next; + else + token = parens_expression(token, &expr, "in attribute"); + } return token; } diff --git a/validation/attribute-nonnull-empty.c b/validation/attribute-nonnull-empty.c new file mode 100644 index 00000000..c4021f61 --- /dev/null +++ b/validation/attribute-nonnull-empty.c @@ -0,0 +1,12 @@ +/* + * An empty attribute argument list, like __attribute__((nonnull())), is + * accepted by GCC and Clang (equivalent to the bare __attribute__((nonnull))) + * and must be parsed by sparse too. + */ +extern void *bare (void *d, const void *s) __attribute__((nonnull)); +extern void *empty(void *d, const void *s) __attribute__((nonnull())); +extern void *args (void *d, const void *s) __attribute__((nonnull(1, 2))); + +/* + * check-name: attribute with empty argument list + */ -- 2.53.0-Meta