Module Name: src
Committed By: rillig
Date: Tue Jan 9 23:46:54 UTC 2024
Modified Files:
src/tests/usr.bin/xlint/lint1: d_bltinoffsetof.c
src/usr.bin/xlint/lint1: cgram.y externs1.h init.c lint1.h tree.c
Log Message:
lint: allow complex offsetof(type, member-designator)
Both GCC 11 and Clang 8 accept member-designators that are not
identifiers but designator sequences, such as in 'offsetof(struct stat,
st_atim.tv_sec)', so make lint accept them as well.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/xlint/lint1/d_bltinoffsetof.c
cvs rdiff -u -r1.477 -r1.478 src/usr.bin/xlint/lint1/cgram.y
cvs rdiff -u -r1.209 -r1.210 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.253 -r1.254 src/usr.bin/xlint/lint1/init.c
cvs rdiff -u -r1.206 -r1.207 src/usr.bin/xlint/lint1/lint1.h
cvs rdiff -u -r1.591 -r1.592 src/usr.bin/xlint/lint1/tree.c
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/d_bltinoffsetof.c
diff -u src/tests/usr.bin/xlint/lint1/d_bltinoffsetof.c:1.2 src/tests/usr.bin/xlint/lint1/d_bltinoffsetof.c:1.3
--- src/tests/usr.bin/xlint/lint1/d_bltinoffsetof.c:1.2 Sun Jan 31 14:39:31 2021
+++ src/tests/usr.bin/xlint/lint1/d_bltinoffsetof.c Tue Jan 9 23:46:54 2024
@@ -1,14 +1,48 @@
-/* $NetBSD: d_bltinoffsetof.c,v 1.2 2021/01/31 14:39:31 rillig Exp $ */
+/* $NetBSD: d_bltinoffsetof.c,v 1.3 2024/01/09 23:46:54 rillig Exp $ */
# 3 "d_bltinoffsetof.c"
struct foo {
- int a;
- char *b;
+ union {
+ struct {
+ struct {
+ int a;
+ int b;
+ } first;
+ char *second;
+ } s;
+ unsigned char padding[1000];
+ } u;
+ union {
+ int a;
+ double b;
+ } array[50];
};
+typedef int first[-(int)__builtin_offsetof(struct foo, u.s.first)];
+typedef int first_a[-(int)__builtin_offsetof(struct foo, u.s.first.a)];
+/* expect+1: ... (-4) ... */
+typedef int first_b[-(int)__builtin_offsetof(struct foo, u.s.first.b)];
+/* expect+1: ... (-8) ... */
+typedef int second[-(int)__builtin_offsetof(struct foo, u.s.second)];
-int
-main(void)
-{
- return __builtin_offsetof(struct foo, b);
-}
+/* expect+1: ... (-1000) ... */
+typedef int array[-(int)__builtin_offsetof(struct foo, array)];
+/* expect+1: ... (-1000) ... */
+typedef int array_0_a[-(int)__builtin_offsetof(struct foo, array[0].a)];
+/* expect+1: ... (-1000) ... */
+typedef int array_0_b[-(int)__builtin_offsetof(struct foo, array[0].b)];
+/* expect+1: ... (-1008) ... */
+typedef int array_1_a[-(int)__builtin_offsetof(struct foo, array[1].a)];
+
+// There is no element array[50], but pointing right behind the last element
+// may be fine.
+/* expect+1: ... (-1400) ... */
+typedef int array_50_a[-(int)__builtin_offsetof(struct foo, array[50].a)];
+/* expect+1: ... (-1400) ... */
+typedef int sizeof_foo[-(int)sizeof(struct foo)];
+
+
+// 51 is out of bounds, as it is larger than the size of the struct.
+// No warning though, maybe later.
+/* expect+1: ... (-1408) ... */
+typedef int array_51_a[-(int)__builtin_offsetof(struct foo, array[51].a)];
Index: src/usr.bin/xlint/lint1/cgram.y
diff -u src/usr.bin/xlint/lint1/cgram.y:1.477 src/usr.bin/xlint/lint1/cgram.y:1.478
--- src/usr.bin/xlint/lint1/cgram.y:1.477 Sun Dec 3 18:17:41 2023
+++ src/usr.bin/xlint/lint1/cgram.y Tue Jan 9 23:46:54 2024
@@ -1,5 +1,5 @@
%{
-/* $NetBSD: cgram.y,v 1.477 2023/12/03 18:17:41 rillig Exp $ */
+/* $NetBSD: cgram.y,v 1.478 2024/01/09 23:46:54 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.477 2023/12/03 18:17:41 rillig Exp $");
+__RCSID("$NetBSD: cgram.y,v 1.478 2024/01/09 23:46:54 rillig Exp $");
#endif
#include <limits.h>
@@ -154,6 +154,7 @@ is_either(const char *s, const char *a,
struct generic_association *y_generic;
struct array_size y_array_size;
bool y_in_system_header;
+ designation y_designation;
};
/* for Bison:
@@ -289,6 +290,7 @@ is_either(const char *s, const char *a,
%type <y_name> identifier
%type <y_string> string
%type <y_tnode> primary_expression
+%type <y_designation> member_designator
%type <y_tnode> generic_selection
%type <y_generic> generic_assoc_list
%type <y_generic> generic_association
@@ -499,10 +501,28 @@ primary_expression:
}
| generic_selection
/* GCC primary-expression, see c_parser_postfix_expression */
- /* TODO: C99 7.17p3 allows not only an identifier but a designator. */
-| T_BUILTIN_OFFSETOF T_LPAREN type_name T_COMMA identifier T_RPAREN {
+| T_BUILTIN_OFFSETOF T_LPAREN type_name T_COMMA {
set_symtyp(FMEMBER);
- $$ = build_offsetof($3, getsym($5));
+ } member_designator T_RPAREN {
+ $$ = build_offsetof($3, $6);
+ }
+;
+
+/* K&R ---, C90 ---, C99 7.17p3, C11 7.19p3, C23 7.21p4 */
+member_designator:
+ identifier {
+ $$ = (designation) { .dn_len = 0 };
+ designation_push(&$$, DK_STRUCT /* or union */, getsym($1), 0);
+ }
+| member_designator T_LBRACK range T_RBRACK {
+ $$ = $1;
+ designation_push(&$$, DK_ARRAY, NULL, $3.lo);
+ }
+| member_designator T_POINT {
+ set_symtyp(FMEMBER);
+ } identifier {
+ $$ = $1;
+ designation_push(&$$, DK_STRUCT /* or union */, getsym($4), 0);
}
;
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.209 src/usr.bin/xlint/lint1/externs1.h:1.210
--- src/usr.bin/xlint/lint1/externs1.h:1.209 Sun Dec 10 15:29:38 2023
+++ src/usr.bin/xlint/lint1/externs1.h Tue Jan 9 23:46:54 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.209 2023/12/10 15:29:38 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.210 2024/01/09 23:46:54 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -289,7 +289,7 @@ tnode_t *promote(op_t, bool, tnode_t *);
tnode_t *convert(op_t, int, type_t *, tnode_t *);
void convert_constant(op_t, int, const type_t *, val_t *, val_t *);
tnode_t *build_sizeof(const type_t *);
-tnode_t *build_offsetof(const type_t *, const sym_t *);
+tnode_t *build_offsetof(const type_t *, designation);
tnode_t *build_alignof(const type_t *);
tnode_t *cast(tnode_t *, type_t *);
tnode_t *build_function_argument(tnode_t *, tnode_t *);
@@ -368,6 +368,7 @@ void init_expr(tnode_t *);
void begin_designation(void);
void add_designator_member(sbuf_t *);
void add_designator_subscript(range_t);
+void designation_push(designation *, designator_kind, const sym_t *, size_t);
/*
* emit.c
Index: src/usr.bin/xlint/lint1/init.c
diff -u src/usr.bin/xlint/lint1/init.c:1.253 src/usr.bin/xlint/lint1/init.c:1.254
--- src/usr.bin/xlint/lint1/init.c:1.253 Sun Dec 10 14:59:47 2023
+++ src/usr.bin/xlint/lint1/init.c Tue Jan 9 23:46:54 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: init.c,v 1.253 2023/12/10 14:59:47 rillig Exp $ */
+/* $NetBSD: init.c,v 1.254 2024/01/09 23:46:54 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: init.c,v 1.253 2023/12/10 14:59:47 rillig Exp $");
+__RCSID("$NetBSD: init.c,v 1.254 2024/01/09 23:46:54 rillig Exp $");
#endif
#include <stdlib.h>
@@ -76,41 +76,6 @@ __RCSID("$NetBSD: init.c,v 1.253 2023/12
*/
-typedef enum designator_kind {
- DK_STRUCT, /* .member */
- DK_UNION, /* .member */
- DK_ARRAY, /* [subscript] */
- /* TODO: actually necessary? */
- DK_SCALAR /* no textual representation, not generated by
- * the parser */
-} designator_kind;
-
-/*
- * A single component on the path from the "current object" of a brace level
- * to the sub-object that is initialized by an expression.
- *
- * C99 6.7.8p6, 6.7.8p7
- */
-typedef struct designator {
- designator_kind dr_kind;
- const sym_t *dr_member; /* for DK_STRUCT and DK_UNION */
- size_t dr_subscript; /* for DK_ARRAY */
- bool dr_done;
-} designator;
-
-/*
- * The path from the "current object" of a brace level to the sub-object that
- * is initialized by an expression. Examples of designations are '.member'
- * or '.member[123].member.member[1][1]'.
- *
- * C99 6.7.8p6, 6.7.8p7
- */
-typedef struct designation {
- designator *dn_items;
- size_t dn_len;
- size_t dn_cap;
-} designation;
-
/*
* Everything that happens between a '{' and the corresponding '}', as part
* of an initialization.
@@ -424,7 +389,7 @@ designation_last(designation *dn)
return &dn->dn_items[dn->dn_len - 1];
}
-static void
+void
designation_push(designation *dn, designator_kind kind,
const sym_t *member, size_t subscript)
{
Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.206 src/usr.bin/xlint/lint1/lint1.h:1.207
--- src/usr.bin/xlint/lint1/lint1.h:1.206 Sat Jan 6 15:05:24 2024
+++ src/usr.bin/xlint/lint1/lint1.h Tue Jan 9 23:46:54 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: lint1.h,v 1.206 2024/01/06 15:05:24 rillig Exp $ */
+/* $NetBSD: lint1.h,v 1.207 2024/01/09 23:46:54 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -480,6 +480,41 @@ typedef struct {
size_t hi; /* inclusive */
} range_t;
+typedef enum designator_kind {
+ DK_STRUCT, /* .member */
+ DK_UNION, /* .member */
+ DK_ARRAY, /* [subscript] */
+ /* TODO: actually necessary? */
+ DK_SCALAR /* no textual representation, not generated by
+ * the parser */
+} designator_kind;
+
+/*
+ * A single component on the path from the "current object" of a brace level
+ * to the sub-object that is initialized by an expression.
+ *
+ * C99 6.7.8p6, 6.7.8p7
+ */
+typedef struct designator {
+ designator_kind dr_kind;
+ const sym_t *dr_member; /* for DK_STRUCT and DK_UNION */
+ size_t dr_subscript; /* for DK_ARRAY */
+ bool dr_done;
+} designator;
+
+/*
+ * The path from the "current object" of a brace level to the sub-object that
+ * is initialized by an expression. Examples of designations are '.member'
+ * or '.member[123].member.member[1][1]'.
+ *
+ * C99 6.7.8p6, 6.7.8p7
+ */
+typedef struct designation {
+ designator *dn_items;
+ size_t dn_len;
+ size_t dn_cap;
+} designation;
+
typedef enum {
LC_ARGSUSED,
LC_BITFIELDTYPE,
Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.591 src/usr.bin/xlint/lint1/tree.c:1.592
--- src/usr.bin/xlint/lint1/tree.c:1.591 Sun Jan 7 12:43:16 2024
+++ src/usr.bin/xlint/lint1/tree.c Tue Jan 9 23:46:54 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.591 2024/01/07 12:43:16 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.592 2024/01/09 23:46:54 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: tree.c,v 1.591 2024/01/07 12:43:16 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.592 2024/01/09 23:46:54 rillig Exp $");
#endif
#include <float.h>
@@ -3884,7 +3884,7 @@ build_sizeof(const type_t *tp)
}
tnode_t *
-build_offsetof(const type_t *tp, const sym_t *sym)
+build_offsetof(const type_t *tp, designation dn)
{
unsigned int offset_in_bits = 0;
@@ -3893,13 +3893,29 @@ build_offsetof(const type_t *tp, const s
error(111, "offsetof");
goto proceed;
}
- sym_t *mem = find_member(tp->t_sou, sym->s_name);
- if (mem == NULL) {
- /* type '%s' does not have member '%s' */
- error(101, sym->s_name, type_name(tp));
- goto proceed;
+ for (size_t i = 0; i < dn.dn_len; i++) {
+ const designator *dr = dn.dn_items + i;
+ if (dr->dr_kind == DK_ARRAY) {
+ if (tp->t_tspec != ARRAY)
+ goto proceed; /* silent error */
+ tp = tp->t_subt;
+ offset_in_bits += (unsigned) dr->dr_subscript
+ * type_size_in_bits(tp);
+ } else {
+ if (!is_struct_or_union(tp->t_tspec))
+ goto proceed; /* silent error */
+ const char *name = dr->dr_member->s_name;
+ sym_t *mem = find_member(tp->t_sou, name);
+ if (mem == NULL) {
+ /* type '%s' does not have member '%s' */
+ error(101, name, type_name(tp));
+ goto proceed;
+ }
+ tp = mem->s_type;
+ offset_in_bits += mem->u.s_member.sm_offset_in_bits;
+ }
}
- offset_in_bits = mem->u.s_member.sm_offset_in_bits;
+ free(dn.dn_items);
proceed:;
unsigned int offset_in_bytes = offset_in_bits / CHAR_SIZE;