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;