Module Name: src Committed By: rillig Date: Wed May 1 17:42:58 UTC 2024
Modified Files: src/tests/usr.bin/xlint/lint1: decl.c src/usr.bin/xlint/lint1: tree.c Log Message: lint: make 'offsetof(t, array-member)' a constant expression The macro 'offsetof(t, m)' already expanded to a constant expression for scalar members but not for arrays. This was because the macro expanded to '(size_t)(((t *)0)->m)', which lint internally represents as 'addr(indir(ptr(0) + offset(m)))', and build_address simplifies 'addr(indir(x))' to 'x' if the types match. The types only match for scalar types though, but not for arrays. When build_address happens, the type information is incomplete, therefore 'offsetof(t, array)' has to be simplified at a later point. To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.30 src/tests/usr.bin/xlint/lint1/decl.c cvs rdiff -u -r1.638 -r1.639 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/decl.c diff -u src/tests/usr.bin/xlint/lint1/decl.c:1.29 src/tests/usr.bin/xlint/lint1/decl.c:1.30 --- src/tests/usr.bin/xlint/lint1/decl.c:1.29 Wed May 1 12:36:56 2024 +++ src/tests/usr.bin/xlint/lint1/decl.c Wed May 1 17:42:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: decl.c,v 1.29 2024/05/01 12:36:56 rillig Exp $ */ +/* $NetBSD: decl.c,v 1.30 2024/05/01 17:42:57 rillig Exp $ */ # 3 "decl.c" /* @@ -243,22 +243,29 @@ get_x(struct point3d { struct point3d_nu } // Expressions of the form '(size_t)&null_ptr->member' are used by several -// C implementations to implement the offsetof macro. Dereferencing a null -// pointer invokes undefined behavior, though, even in this form. +// C implementations to implement the offsetof macro. void offsetof_on_array_member(void) { - struct s1 { + typedef struct { int padding, plain, arr[2]; - }; + } s1; + // Bit-fields must have a constant number of bits. struct s2 { - unsigned int off_plain:(unsigned long)&((struct s1 *)0)->plain; - // FIXME: offsetof must work for array members as well. - /* expect+1: error: integral constant expression expected [55] */ - unsigned int off_arr:(unsigned long)&((struct s1 *)0)->arr; - // FIXME: offsetof must work for array members as well. - /* expect+1: error: integral constant expression expected [55] */ - unsigned int off_arr_element:(unsigned long)&((struct s1 *)0)->arr[0]; + unsigned int off_plain:(unsigned long)&((s1 *)0)->plain; + unsigned int off_arr:(unsigned long)&((s1 *)0)->arr; + unsigned int off_arr_0:(unsigned long)&((s1 *)0)->arr[0]; + unsigned int off_arr_3:(unsigned long)&((s1 *)0)->arr[3]; }; + + // Arrays may be variable-width, but the diagnostic reveals the size. + /* expect+1: error: negative array dimension (-4) [20] */ + typedef int off_plain[-(int)(unsigned long)&((s1 *)0)->plain]; + /* expect+1: error: negative array dimension (-8) [20] */ + typedef int off_arr[-(int)(unsigned long)&((s1 *)0)->arr]; + /* expect+1: error: negative array dimension (-8) [20] */ + typedef int off_arr_0[-(int)(unsigned long)&((s1 *)0)->arr[0]]; + /* expect+1: error: negative array dimension (-20) [20] */ + typedef int off_arr_3[-(int)(unsigned long)&((s1 *)0)->arr[3]]; } Index: src/usr.bin/xlint/lint1/tree.c diff -u src/usr.bin/xlint/lint1/tree.c:1.638 src/usr.bin/xlint/lint1/tree.c:1.639 --- src/usr.bin/xlint/lint1/tree.c:1.638 Wed May 1 05:49:33 2024 +++ src/usr.bin/xlint/lint1/tree.c Wed May 1 17:42:57 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.638 2024/05/01 05:49:33 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.639 2024/05/01 17:42:57 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.638 2024/05/01 05:49:33 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.639 2024/05/01 17:42:57 rillig Exp $"); #endif #include <float.h> @@ -4112,6 +4112,28 @@ cast_to_union(tnode_t *otn, bool sys, ty return NULL; } +// In GCC mode, allow 'nullptr + offset' as a constant expression. +static tnode_t * +null_pointer_offset(tnode_t *tn) +{ + uint64_t off = 0; + const tnode_t *n = tn; + while ((n->tn_op == PLUS || n->tn_op == MINUS) + && is_integer(n->u.ops.right->tn_type->t_tspec)) { + off += (uint64_t)n->u.ops.right->u.value.u.integer; + n = n->u.ops.left; + } + if (n->tn_type->t_tspec == PTR + && n->tn_op == ADDR + && n->u.ops.left->tn_op == INDIR + && n->u.ops.left->u.ops.left->tn_op == CON + && n->u.ops.left->u.ops.left->tn_type->t_tspec == PTR) { + off += (uint64_t)n->u.ops.left->u.ops.left->u.value.u.integer; + return build_integer_constant(SIZEOF_TSPEC, (int64_t)off); + } + return tn; +} + tnode_t * cast(tnode_t *tn, bool sys, type_t *tp) { @@ -4144,7 +4166,7 @@ cast(tnode_t *tn, bool sys, type_t *tp) error(148); return NULL; } else if (is_integer(nt) && is_scalar(ot)) { - /* ok */ + tn = null_pointer_offset(tn); } else if (is_floating(nt) && is_arithmetic(ot)) { /* ok */ } else if (nt == PTR && is_integer(ot)) {