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;

Reply via email to