Module Name: src
Committed By: rillig
Date: Sat May 11 16:12:28 UTC 2024
Modified Files:
src/tests/usr.bin/xlint/lint1: c23.c
src/usr.bin/xlint/lint1: cgram.y debug.c externs1.h lint1.h scan.l
Log Message:
lint: parse but otherwise ignore C23 attributes
The C23 attributes are only parsed before an expression in an expression
statement, as a proof of concept. Other places will follow later.
To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/tests/usr.bin/xlint/lint1/c23.c
cvs rdiff -u -r1.499 -r1.500 src/usr.bin/xlint/lint1/cgram.y
cvs rdiff -u -r1.78 -r1.79 src/usr.bin/xlint/lint1/debug.c
cvs rdiff -u -r1.225 -r1.226 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.226 -r1.227 src/usr.bin/xlint/lint1/lint1.h
cvs rdiff -u -r1.140 -r1.141 src/usr.bin/xlint/lint1/scan.l
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/tests/usr.bin/xlint/lint1/c23.c
diff -u src/tests/usr.bin/xlint/lint1/c23.c:1.12 src/tests/usr.bin/xlint/lint1/c23.c:1.13
--- src/tests/usr.bin/xlint/lint1/c23.c:1.12 Thu May 9 20:56:41 2024
+++ src/tests/usr.bin/xlint/lint1/c23.c Sat May 11 16:12:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: c23.c,v 1.12 2024/05/09 20:56:41 rillig Exp $ */
+/* $NetBSD: c23.c,v 1.13 2024/05/11 16:12:28 rillig Exp $ */
# 3 "c23.c"
// Tests for the option -Ac23, which allows features from C23 and all earlier
@@ -109,3 +109,57 @@ thread_local extern int extern_thread_lo
static thread_local int static_thread_local_1;
/* expect+1: warning: static variable 'static_thread_local_2' unused [226] */
thread_local static int static_thread_local_2;
+
+
+int
+attributes(int i)
+{
+ // An attribute specifier list may be empty.
+ [[]]i++;
+
+ // There may be leading or trailing commas.
+ [[,]]i++;
+
+ // There may be arbitrary commas around or between the attributes.
+ [[,,,,,]]i++;
+
+ // An attribute may be a plain identifier without arguments.
+ [[identifier]]i++;
+
+ // The identifier may be prefixed with one additional identifier.
+ [[prefix::identifier]]i++;
+
+ // An attribute may have empty arguments.
+ [[identifier()]]i++;
+
+ // The arguments of an attribute may be arbitrary tokens.
+ [[identifier([])]]i++;
+
+ // The commas in this "argument list" are ordinary punctuator tokens,
+ // they do not separate any arguments.
+ // The structure of the attribute argument is:
+ // 1. empty balanced token sequence between '[' and ']'
+ // 2. token ','
+ // 3. empty balanced token sequence between '{' and '}'
+ // 4. token ','
+ // 5. empty balanced token sequence between '(' and ')'
+ [[identifier([], {}, ())]]i++;
+
+ // Inside an argument, parentheses may be nested.
+ [[identifier(((((())))))]]i++;
+ // Inside an argument, brackets may be nested.
+ [[identifier([[[[[]]]]])]]i++;
+ // Inside an argument, braces may be nested.
+ [[identifier({{{{{}}}}})]]i++;
+
+ // An attribute argument may contain arbitrary punctuation.
+ [[identifier(++++ ? ? ? : : :: )]]i++;
+
+ // An attribute argument may contain constants and string literals.
+ [[identifier(0, 0.0, "hello" " " "world")]]i++;
+
+ // There may be multiple attribute specifier sequences in a row.
+ [[]][[]][[]]i++;
+
+ return i;
+}
Index: src/usr.bin/xlint/lint1/cgram.y
diff -u src/usr.bin/xlint/lint1/cgram.y:1.499 src/usr.bin/xlint/lint1/cgram.y:1.500
--- src/usr.bin/xlint/lint1/cgram.y:1.499 Thu May 9 20:56:41 2024
+++ src/usr.bin/xlint/lint1/cgram.y Sat May 11 16:12:28 2024
@@ -1,5 +1,5 @@
%{
-/* $NetBSD: cgram.y,v 1.499 2024/05/09 20:56:41 rillig Exp $ */
+/* $NetBSD: cgram.y,v 1.500 2024/05/11 16:12:28 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: cgram.y,v 1.499 2024/05/09 20:56:41 rillig Exp $");
+__RCSID("$NetBSD: cgram.y,v 1.500 2024/05/11 16:12:28 rillig Exp $");
#endif
#include <limits.h>
@@ -69,6 +69,7 @@ static int saved_lwarn = LWARN_NOTHING_S
static void cgram_declare(sym_t *, bool, sbuf_t *);
static void read_until_rparen(void);
+static balanced_token_sequence read_balanced_token_sequence(void);
static sym_t *symbolrename(sym_t *, sbuf_t *);
@@ -110,6 +111,42 @@ is_either(const char *s, const char *a,
return strcmp(s, a) == 0 || strcmp(s, b) == 0;
}
+static void
+attribute_list_add(attribute_list *list, attribute attr)
+{
+ if (list->len >= list->cap) {
+ attribute *old_attrs = list->attrs;
+ list->cap = 16 + 2 * list->cap;
+ list->attrs = block_zero_alloc(
+ list->cap * sizeof(*list->attrs), "attribute_list.attrs");
+ memcpy(list->attrs, old_attrs,
+ list->len * sizeof(*list->attrs));
+ }
+ list->attrs[list->len++] = attr;
+}
+
+static void
+attribute_list_add_all(attribute_list *dst, attribute_list src)
+{
+ for (size_t i = 0, n = src.len; i < n; i++)
+ attribute_list_add(dst, src.attrs[i]);
+}
+
+static attribute
+new_attribute(const sbuf_t *prefix, const sbuf_t *name,
+ const balanced_token_sequence *arg)
+{
+ attribute attr = { .name = xstrdup(name->sb_name) };
+ if (prefix != NULL)
+ attr.prefix = xstrdup(prefix->sb_name);
+ if (arg != NULL) {
+ attr.arg = block_zero_alloc(sizeof(*attr.arg),
+ "balanced_token_sequence");
+ *attr.arg = *arg;
+ }
+ return attr;
+}
+
#if YYDEBUG && YYBYACC
#define YYSTYPE_TOSTRING cgram_to_string
#endif
@@ -141,6 +178,9 @@ is_either(const char *s, const char *a,
bool y_in_system_header;
designation y_designation;
named_constant y_named_constant;
+ attribute y_attribute;
+ attribute_list y_attribute_list;
+ balanced_token_sequence y_tokens;
};
/* for Bison:
@@ -231,6 +271,7 @@ is_either(const char *s, const char *a,
%token T_COMMA
%token T_SEMI
%token T_ELLIPSIS
+%token T_DCOLON
%token T_REAL
%token T_IMAG
%token T_GENERIC
@@ -388,6 +429,11 @@ is_either(const char *s, const char *a,
%type <y_range> range
/* No type for init_lbrace. */
/* No type for init_rbrace. */
+%type <y_attribute_list> attribute_specifier_sequence
+%type <y_attribute_list> attribute_specifier
+%type <y_attribute_list> attribute_list
+%type <y_attribute> attribute
+%type <y_tokens> attribute_argument_clause
%type <y_name> asm_or_symbolrename_opt
/* No type for statement. */
/* No type for no_attr_statement. */
@@ -1854,27 +1900,71 @@ init_rbrace: /* helper */
}
;
-/* TODO: Implement 'attribute_specifier_sequence' from C23 6.7.13.2. */
-
-/* TODO: Implement 'attribute_specifier' from C23 6.7.13.2. */
-
-/* TODO: Implement 'attribute_list' from C23 6.7.13.2. */
-
-/* TODO: Implement 'attribute' from C23 6.7.13.2. */
-
-/* TODO: Implement 'attribute_token' from C23 6.7.13.2. */
+/* C23 6.7.13.2 */
+attribute_specifier_sequence:
+ attribute_specifier {
+ $$ = (attribute_list) { NULL, 0, 0 };
+ attribute_list_add_all(&$$, $1);
+ }
+| attribute_specifier_sequence attribute_specifier {
+ $$ = $1;
+ attribute_list_add_all(&$$, $2);
+ }
+;
-/* TODO: Implement 'standard_attribute' from C23 6.7.13.2. */
+/* C23 6.7.13.2 */
+attribute_specifier:
+ T_LBRACK T_LBRACK attribute_list T_RBRACK T_RBRACK {
+ $$ = $3;
+ }
+;
-/* TODO: Implement 'attribute_prefixed_token' from C23 6.7.13.2. */
+/* C23 6.7.13.2 */
+attribute_list:
+ /* empty */ {
+ $$ = (attribute_list) { NULL, 0, 0 };
+ }
+| attribute {
+ $$ = (attribute_list) { NULL, 0, 0 };
+ attribute_list_add(&$$, $1);
+ }
+| attribute_list T_COMMA
+| attribute_list T_COMMA attribute {
+ $$ = $1;
+ attribute_list_add(&$$, $3);
+ }
+;
-/* TODO: Implement 'attribute_prefix' from C23 6.7.13.2. */
+/* C23 6.7.13.2 */
+attribute:
+ identifier {
+ $$ = new_attribute(NULL, $1, NULL);
+ }
+| identifier T_DCOLON identifier {
+ $$ = new_attribute($1, $3, NULL);
+ }
+| identifier attribute_argument_clause {
+ $$ = new_attribute(NULL, $1, &$2);
+ }
+| identifier T_DCOLON identifier attribute_argument_clause {
+ $$ = new_attribute($1, $3, &$4);
+ }
+;
-/* TODO: Implement 'attribute_argument_clause' from C23 6.7.13.2. */
+/* The rule 'attribute_token' is inlined into 'attribute'. */
+/* The rule 'standard_attribute' is inlined into 'attribute_token'. */
+/* The rule 'attribute_prefixed_token' is inlined into 'attribute_token'. */
+/* The rule 'attribute_prefix' is inlined into 'attribute_token'. */
-/* TODO: Implement 'balanced_token_sequence' from C23 6.7.13.2. */
+/* C23 6.7.13.2 */
+attribute_argument_clause:
+ T_LPAREN {
+ $$ = read_balanced_token_sequence();
+ }
+;
-/* TODO: Implement 'balanced_token' from C23 6.7.13.2. */
+/* The rule 'balanced_token_sequence' is inlined into 'attribute_argument_clause'. */
+/* The rule 'balanced_token' is inlined into 'balanced_token_sequence'. */
asm_or_symbolrename_opt: /* GCC extensions */
/* empty */ {
@@ -2013,6 +2103,11 @@ expression_statement:
check_statement_reachable();
suppress_fallthrough = false;
}
+| attribute_specifier_sequence expression T_SEMI {
+ debug_attribute_list(&$1);
+ expr($2, false, false, false, false);
+ suppress_fallthrough = false;
+ }
;
/* C99 6.8.4, C23 6.8.5.1 */
@@ -2404,10 +2499,10 @@ yyerror(const char *msg)
#if YYDEBUG && YYBYACC
static const char *
-cgram_to_string(int token, YYSTYPE val)
+cgram_to_string(int tok, YYSTYPE val)
{
- switch (token) {
+ switch (tok) {
case T_INCDEC:
return val.y_inc ? "++" : "--";
case T_MULTIPLICATIVE:
@@ -2467,6 +2562,82 @@ read_until_rparen(void)
yyclearin;
}
+static void
+fill_token(token *tok)
+{
+ switch (yychar) {
+ case T_NAME:
+ case T_TYPENAME:
+ tok->kind = TK_IDENTIFIER;
+ tok->u.identifier = xstrdup(yylval.y_name->sb_name);
+ break;
+ case T_CON:
+ tok->kind = TK_CONSTANT;
+ tok->u.constant = *yylval.y_val;
+ break;
+ case T_NAMED_CONSTANT:
+ tok->kind = TK_IDENTIFIER;
+ tok->u.identifier = xstrdup(yytext);
+ break;
+ case T_STRING:;
+ tok->kind = TK_STRING_LITERALS;
+ tok->u.string_literals.len = yylval.y_string->len;
+ tok->u.string_literals.cap = yylval.y_string->cap;
+ tok->u.string_literals.data = xstrdup(yylval.y_string->data);
+ break;
+ default:
+ tok->kind = TK_PUNCTUATOR;
+ tok->u.punctuator = xstrdup(yytext);
+ }
+}
+
+static void
+seq_reserve(balanced_token_sequence *seq)
+{
+ if (seq->len >= seq->cap) {
+ seq->cap = 16 + 2 * seq->cap;
+ const balanced_token *old_tokens = seq->tokens;
+ balanced_token *new_tokens = block_zero_alloc(
+ seq->cap * sizeof(*seq->tokens), "balanced_tokens");
+ memcpy(new_tokens, old_tokens, seq->len * sizeof(*seq->tokens));
+ seq->tokens = new_tokens;
+ }
+}
+
+static balanced_token_sequence
+read_balanced(int opening)
+{
+ debug_enter();
+ int closing = opening == T_LPAREN ? T_RPAREN
+ : opening == T_LBRACK ? T_RBRACK : T_RBRACE;
+ balanced_token_sequence seq = { NULL, 0, 0 };
+ debug_step("opening %d, closing %d", opening, closing);
+
+ while (yychar = yylex(), yychar > 0 && yychar != closing) {
+ debug_step("reading token %d", yychar);
+ seq_reserve(&seq);
+ if (yychar == T_LPAREN
+ || yychar == T_LBRACK
+ || yychar == T_LBRACE) {
+ seq.tokens[seq.len].kind = yychar == T_LPAREN ? '('
+ : yychar == T_LBRACK ? '[' : '{';
+ seq.tokens[seq.len++].u.tokens = read_balanced(yychar);
+ } else
+ fill_token(&seq.tokens[seq.len++].u.token);
+ }
+ debug_leave();
+ return seq;
+}
+
+static balanced_token_sequence
+read_balanced_token_sequence(void)
+{
+ lint_assert(yychar < 0);
+ balanced_token_sequence seq = read_balanced(T_LPAREN);
+ yyclearin;
+ return seq;
+}
+
static sym_t *
symbolrename(sym_t *s, sbuf_t *sb)
{
Index: src/usr.bin/xlint/lint1/debug.c
diff -u src/usr.bin/xlint/lint1/debug.c:1.78 src/usr.bin/xlint/lint1/debug.c:1.79
--- src/usr.bin/xlint/lint1/debug.c:1.78 Thu May 9 11:08:07 2024
+++ src/usr.bin/xlint/lint1/debug.c Sat May 11 16:12:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: debug.c,v 1.78 2024/05/09 11:08:07 rillig Exp $ */
+/* $NetBSD: debug.c,v 1.79 2024/05/11 16:12:28 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: debug.c,v 1.78 2024/05/09 11:08:07 rillig Exp $");
+__RCSID("$NetBSD: debug.c,v 1.79 2024/05/11 16:12:28 rillig Exp $");
#endif
#include <stdlib.h>
@@ -526,4 +526,73 @@ debug_dcs_all(void)
debug_decl_level(dl);
}
}
+
+static void
+debug_token(const token *tok)
+{
+ switch (tok->kind) {
+ case TK_IDENTIFIER:
+ debug_printf("%s", tok->u.identifier);
+ break;
+ case TK_CONSTANT:;
+ val_t c = tok->u.constant;
+ tspec_t t = c.v_tspec;
+ if (is_floating(t))
+ debug_printf("%Lg", c.u.floating);
+ else if (is_uinteger(t))
+ debug_printf("%llu", (unsigned long long)c.u.integer);
+ else if (is_integer(t))
+ debug_printf("%lld", (long long)c.u.integer);
+ else {
+ lint_assert(t == BOOL);
+ debug_printf("%s",
+ c.u.integer != 0 ? "true" : "false");
+ }
+ break;
+ case TK_STRING_LITERALS:
+ debug_printf("%s", tok->u.string_literals.data);
+ break;
+ case TK_PUNCTUATOR:
+ debug_printf("%s", tok->u.punctuator);
+ break;
+ }
+}
+
+static void
+debug_balanced_token_sequence(const balanced_token_sequence *seq)
+{
+ const char *sep = "";
+ for (size_t i = 0, n = seq->len; i < n; i++) {
+ const balanced_token *tok = seq->tokens + i;
+ if (tok->kind != '\0') {
+ debug_printf("%s%c", sep, tok->kind);
+ debug_balanced_token_sequence(&tok->u.tokens);
+ debug_printf("%c", tok->kind == '(' ? ')'
+ : tok->kind == '[' ? ']' : '}');
+ } else {
+ debug_printf("%s", sep);
+ debug_token(&tok->u.token);
+ }
+ sep = " ";
+ }
+}
+
+void
+debug_attribute_list(const attribute_list *list)
+{
+ for (size_t i = 0, n = list->len; i < n; i++) {
+ const attribute *attr = list->attrs + i;
+ debug_printf("attribute [[");
+ if (attr->prefix != NULL)
+ debug_printf("%s::", attr->prefix);
+ debug_printf("%s", attr->name);
+ if (attr->arg != NULL) {
+ debug_printf("(");
+ debug_balanced_token_sequence(attr->arg);
+ debug_printf(")");
+ }
+ debug_step("]]");
+ }
+}
+
#endif
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.225 src/usr.bin/xlint/lint1/externs1.h:1.226
--- src/usr.bin/xlint/lint1/externs1.h:1.225 Thu May 9 11:08:07 2024
+++ src/usr.bin/xlint/lint1/externs1.h Sat May 11 16:12:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.225 2024/05/09 11:08:07 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.226 2024/05/11 16:12:28 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -152,6 +152,7 @@ void debug_pop_indented(bool);
void debug_enter_func(const char *);
void debug_step(const char *fmt, ...) __printflike(1, 2);
void debug_leave_func(const char *);
+void debug_attribute_list(const attribute_list *);
#define debug_enter() debug_enter_func(__func__)
#define debug_leave() debug_leave_func(__func__)
#else
@@ -171,6 +172,7 @@ void debug_leave_func(const char *);
#define debug_enter() debug_noop()
#define debug_step(...) debug_noop()
#define debug_leave() debug_noop()
+#define debug_attribute_list(list) debug_noop()
#endif
/*
Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.226 src/usr.bin/xlint/lint1/lint1.h:1.227
--- src/usr.bin/xlint/lint1/lint1.h:1.226 Thu May 9 11:08:07 2024
+++ src/usr.bin/xlint/lint1/lint1.h Sat May 11 16:12:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: lint1.h,v 1.226 2024/05/09 11:08:07 rillig Exp $ */
+/* $NetBSD: lint1.h,v 1.227 2024/05/11 16:12:28 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -513,6 +513,52 @@ typedef struct {
bool unescaped_newline; /* stops iterating */
} quoted_iterator;
+typedef enum {
+ TK_IDENTIFIER,
+ TK_CONSTANT,
+ TK_STRING_LITERALS,
+ TK_PUNCTUATOR,
+} token_kind;
+
+typedef struct token {
+ token_kind kind;
+ union {
+ const char *identifier;
+ val_t constant;
+ buffer string_literals;
+ const char *punctuator;
+ } u;
+} token;
+
+typedef struct balanced_token_sequence balanced_token_sequence;
+typedef struct balanced_token balanced_token;
+
+struct balanced_token_sequence {
+ balanced_token *tokens;
+ size_t len;
+ size_t cap;
+};
+
+struct balanced_token {
+ char kind; // '\0', '(', '[', '{'
+ union {
+ token token;
+ balanced_token_sequence tokens;
+ } u;
+};
+
+typedef struct {
+ const char *prefix;
+ const char *name;
+ balanced_token_sequence *arg;
+} attribute;
+
+typedef struct {
+ attribute *attrs;
+ size_t len;
+ size_t cap;
+} attribute_list;
+
#include "externs1.h"
#define lint_assert(cond) \
Index: src/usr.bin/xlint/lint1/scan.l
diff -u src/usr.bin/xlint/lint1/scan.l:1.140 src/usr.bin/xlint/lint1/scan.l:1.141
--- src/usr.bin/xlint/lint1/scan.l:1.140 Thu Sep 14 22:20:08 2023
+++ src/usr.bin/xlint/lint1/scan.l Sat May 11 16:12:28 2024
@@ -1,5 +1,5 @@
%{
-/* $NetBSD: scan.l,v 1.140 2023/09/14 22:20:08 rillig Exp $ */
+/* $NetBSD: scan.l,v 1.141 2024/05/11 16:12:28 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: scan.l,v 1.140 2023/09/14 22:20:08 rillig Exp $");
+__RCSID("$NetBSD: scan.l,v 1.141 2024/05/11 16:12:28 rillig Exp $");
#endif
#include "lint1.h"
@@ -111,6 +111,7 @@ FSUF ([fFlL]?[i]?)
"(" return T_LPAREN;
")" return T_RPAREN;
"..." return T_ELLIPSIS;
+"::" return T_DCOLON;
"'" return lex_character_constant();
"L'" return lex_wide_character_constant();
^#.*$ lex_directive(yytext);