Module Name:    src
Committed By:   rillig
Date:           Fri Jun 30 15:19:10 UTC 2023

Modified Files:
        src/tests/usr.bin/xlint/lint1: expr_sizeof.c msg_065.c
        src/usr.bin/xlint/lint1: decl.c

Log Message:
lint: fix computation of bit-field width

When bit-fields in packed structs were added on 2009-10-02, lint assumed
that they would only use 'signed int' or 'unsigned int' as storage unit,
even though C99 also allows _Bool.

The cleanup commit for decl.c 1.225 from 2021-08-28 accidentally changed
the rounding mode for bit-field storage units from round-up to
round-down.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/tests/usr.bin/xlint/lint1/expr_sizeof.c
cvs rdiff -u -r1.4 -r1.5 src/tests/usr.bin/xlint/lint1/msg_065.c
cvs rdiff -u -r1.325 -r1.326 src/usr.bin/xlint/lint1/decl.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/expr_sizeof.c
diff -u src/tests/usr.bin/xlint/lint1/expr_sizeof.c:1.9 src/tests/usr.bin/xlint/lint1/expr_sizeof.c:1.10
--- src/tests/usr.bin/xlint/lint1/expr_sizeof.c:1.9	Fri Jun 30 09:21:52 2023
+++ src/tests/usr.bin/xlint/lint1/expr_sizeof.c	Fri Jun 30 15:19:09 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: expr_sizeof.c,v 1.9 2023/06/30 09:21:52 rillig Exp $	*/
+/*	$NetBSD: expr_sizeof.c,v 1.10 2023/06/30 15:19:09 rillig Exp $	*/
 # 3 "expr_sizeof.c"
 
 /*
@@ -92,7 +92,7 @@ bit_fields(void)
 			_Bool flag2:1;
 		};
 	} anonymous_flags;
-	/* FIXME: sizeof must be 1, not 0. */
+	/* expect+1: error: negative array dimension (-1) [20] */
 	typedef int sizeof_anonymous_flags[-(int)sizeof(anonymous_flags)];
 
 	struct {

Index: src/tests/usr.bin/xlint/lint1/msg_065.c
diff -u src/tests/usr.bin/xlint/lint1/msg_065.c:1.4 src/tests/usr.bin/xlint/lint1/msg_065.c:1.5
--- src/tests/usr.bin/xlint/lint1/msg_065.c:1.4	Wed Jun 22 19:23:18 2022
+++ src/tests/usr.bin/xlint/lint1/msg_065.c	Fri Jun 30 15:19:09 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: msg_065.c,v 1.4 2022/06/22 19:23:18 rillig Exp $	*/
+/*	$NetBSD: msg_065.c,v 1.5 2023/06/30 15:19:09 rillig Exp $	*/
 # 3 "msg_065.c"
 
 // Test for message: '%s' has no named members [65]
@@ -7,7 +7,7 @@ struct ok {
 	int member;
 };
 
-/* XXX: should generate a warning as well. */
+/* Don't warn about completely empty structs, which are a GCC extension. */
 struct empty {
 };
 

Index: src/usr.bin/xlint/lint1/decl.c
diff -u src/usr.bin/xlint/lint1/decl.c:1.325 src/usr.bin/xlint/lint1/decl.c:1.326
--- src/usr.bin/xlint/lint1/decl.c:1.325	Fri Jun 30 14:39:23 2023
+++ src/usr.bin/xlint/lint1/decl.c	Fri Jun 30 15:19:09 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: decl.c,v 1.325 2023/06/30 14:39:23 rillig Exp $ */
+/* $NetBSD: decl.c,v 1.326 2023/06/30 15:19:09 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: decl.c,v 1.325 2023/06/30 14:39:23 rillig Exp $");
+__RCSID("$NetBSD: decl.c,v 1.326 2023/06/30 15:19:09 rillig Exp $");
 #endif
 
 #include <sys/param.h>
@@ -456,18 +456,20 @@ set_first_typedef(type_t *tp, sym_t *sym
 }
 
 static unsigned int
-bit_field_width(sym_t **mem)
+bit_field_width(sym_t **mem, bool *named)
 {
-	unsigned int width = (*mem)->s_type->t_bit_field_width;
+	unsigned int width = 0;
+	unsigned int align = 0;
 	while (*mem != NULL && (*mem)->s_type->t_bitfield) {
+		if ((*mem)->s_name != unnamed)
+			*named = true;
 		width += (*mem)->s_type->t_bit_field_width;
+		unsigned int mem_align = alignment_in_bits((*mem)->s_type);
+		if (mem_align > align)
+			align = mem_align;
 		*mem = (*mem)->s_next;
 	}
-
-	// XXX: Why INT_SIZE? C99 6.7.2.1p4 allows bit-fields to have type
-	// XXX: _Bool or another implementation-defined type.
-	// XXX: Why round down instead of up? See expr_sizeof.c, anonymous_flags.
-	return width - width % INT_SIZE;
+	return (width + align - 1) & -align;
 }
 
 static void
@@ -481,11 +483,12 @@ pack_struct_or_union(type_t *tp)
 	}
 
 	unsigned int bits = 0;
+	bool named = false;
 	for (sym_t *mem = tp->t_sou->sou_first_member;
 	     mem != NULL; mem = mem->s_next) {
 		// TODO: Maybe update mem->u.s_member.sm_offset_in_bits.
 		if (mem->s_type->t_bitfield) {
-			bits += bit_field_width(&mem);
+			bits += bit_field_width(&mem, &named);
 			if (mem == NULL)
 				break;
 		}
@@ -1795,24 +1798,25 @@ complete_struct_or_union(sym_t *first_me
 		c99ism(47, tspec_name(tp->t_tspec));
 	}
 
-	int n = 0;
+	bool has_named_member = false;
 	for (sym_t *mem = first_member; mem != NULL; mem = mem->s_next) {
+		if (mem->s_name != unnamed)
+			has_named_member = true;
 		/* bind anonymous members to the structure */
 		if (mem->u.s_member.sm_sou_type == NULL) {
 			mem->u.s_member.sm_sou_type = sp;
 			if (mem->s_type->t_bitfield) {
-				sp->sou_size_in_bits += bit_field_width(&mem);
+				sp->sou_size_in_bits +=
+				    bit_field_width(&mem, &has_named_member);
 				if (mem == NULL)
 					break;
 			}
 			sp->sou_size_in_bits +=
 			    type_size_in_bits(mem->s_type);
 		}
-		if (mem->s_name != unnamed)
-			n++;
 	}
 
-	if (n == 0 && sp->sou_size_in_bits != 0) {
+	if (!has_named_member && sp->sou_size_in_bits != 0) {
 		/* '%s' has no named members */
 		warning(65, type_name(tp));
 	}

Reply via email to