Module Name: src
Committed By: rillig
Date: Fri Mar 1 19:39:29 UTC 2024
Modified Files:
src/distrib/sets/lists/tests: mi
src/tests/usr.bin/xlint/lint1: t_usage.sh
src/usr.bin/xlint/lint1: Makefile err.c externs1.h tree.c
Added Files:
src/tests/usr.bin/xlint/lint1: msg_357.c msg_358.c msg_359.c msg_360.c
msg_361.c msg_362.c msg_363.c msg_364.c msg_365.c msg_366.c
msg_367.c msg_368.c msg_369.c msg_370.c msg_371.c msg_372.c
msg_373.c msg_374.c msg_375.c
Log Message:
lint: test format strings from snprintb calls
The functions snprintb and snprintb_m are specific to NetBSD, and their
format strings are tricky to get correct. Provide some assistance in
catching the most common mistakes.
To generate a diff of this commit:
cvs rdiff -u -r1.1306 -r1.1307 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r0 -r1.1 src/tests/usr.bin/xlint/lint1/msg_357.c \
src/tests/usr.bin/xlint/lint1/msg_358.c \
src/tests/usr.bin/xlint/lint1/msg_359.c \
src/tests/usr.bin/xlint/lint1/msg_360.c \
src/tests/usr.bin/xlint/lint1/msg_361.c \
src/tests/usr.bin/xlint/lint1/msg_362.c \
src/tests/usr.bin/xlint/lint1/msg_363.c \
src/tests/usr.bin/xlint/lint1/msg_364.c \
src/tests/usr.bin/xlint/lint1/msg_365.c \
src/tests/usr.bin/xlint/lint1/msg_366.c \
src/tests/usr.bin/xlint/lint1/msg_367.c \
src/tests/usr.bin/xlint/lint1/msg_368.c \
src/tests/usr.bin/xlint/lint1/msg_369.c \
src/tests/usr.bin/xlint/lint1/msg_370.c \
src/tests/usr.bin/xlint/lint1/msg_371.c \
src/tests/usr.bin/xlint/lint1/msg_372.c \
src/tests/usr.bin/xlint/lint1/msg_373.c \
src/tests/usr.bin/xlint/lint1/msg_374.c \
src/tests/usr.bin/xlint/lint1/msg_375.c
cvs rdiff -u -r1.15 -r1.16 src/tests/usr.bin/xlint/lint1/t_usage.sh
cvs rdiff -u -r1.103 -r1.104 src/usr.bin/xlint/lint1/Makefile
cvs rdiff -u -r1.225 -r1.226 src/usr.bin/xlint/lint1/err.c
cvs rdiff -u -r1.216 -r1.217 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.605 -r1.606 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/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.1306 src/distrib/sets/lists/tests/mi:1.1307
--- src/distrib/sets/lists/tests/mi:1.1306 Mon Feb 19 04:30:38 2024
+++ src/distrib/sets/lists/tests/mi Fri Mar 1 19:39:28 2024
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1306 2024/02/19 04:30:38 riastradh Exp $
+# $NetBSD: mi,v 1.1307 2024/03/01 19:39:28 rillig Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@@ -7471,6 +7471,25 @@
./usr/tests/usr.bin/xlint/lint1/msg_354.c tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/xlint/lint1/msg_355.c tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/xlint/lint1/msg_356.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_357.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_358.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_359.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_360.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_361.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_362.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_363.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_364.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_365.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_366.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_367.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_368.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_369.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_370.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_371.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_372.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_373.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_374.c tests-usr.bin-tests compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_375.c tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/xlint/lint1/op_colon.c tests-usr.bin-tests compattestfile,atf
./usr/tests/usr.bin/xlint/lint1/op_colon.exp tests-obsolete obsolete,atf
./usr/tests/usr.bin/xlint/lint1/op_shl_lp64.c tests-usr.bin-tests compattestfile,atf
Index: src/tests/usr.bin/xlint/lint1/t_usage.sh
diff -u src/tests/usr.bin/xlint/lint1/t_usage.sh:1.15 src/tests/usr.bin/xlint/lint1/t_usage.sh:1.16
--- src/tests/usr.bin/xlint/lint1/t_usage.sh:1.15 Sat Feb 3 20:10:11 2024
+++ src/tests/usr.bin/xlint/lint1/t_usage.sh Fri Mar 1 19:39:29 2024
@@ -1,4 +1,4 @@
-# $NetBSD: t_usage.sh,v 1.15 2024/02/03 20:10:11 rillig Exp $
+# $NetBSD: t_usage.sh,v 1.16 2024/03/01 19:39:29 rillig Exp $
#
# Copyright (c) 2023 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -39,13 +39,13 @@ suppress_messages_body()
# The largest known message.
atf_check \
- "$lint1" -X 355 code.c /dev/null
+ "$lint1" -X 375 code.c /dev/null
# Larger than the largest known message.
atf_check \
-s 'exit:1' \
- -e "inline:lint1: invalid message ID '357'\n" \
- "$lint1" -X 357 code.c /dev/null
+ -e "inline:lint1: invalid message ID '376'\n" \
+ "$lint1" -X 376 code.c /dev/null
# Whitespace is not allowed before a message ID.
atf_check \
Index: src/usr.bin/xlint/lint1/Makefile
diff -u src/usr.bin/xlint/lint1/Makefile:1.103 src/usr.bin/xlint/lint1/Makefile:1.104
--- src/usr.bin/xlint/lint1/Makefile:1.103 Tue Feb 6 22:47:21 2024
+++ src/usr.bin/xlint/lint1/Makefile Fri Mar 1 19:39:28 2024
@@ -1,10 +1,10 @@
-# $NetBSD: Makefile,v 1.103 2024/02/06 22:47:21 rillig Exp $
+# $NetBSD: Makefile,v 1.104 2024/03/01 19:39:28 rillig Exp $
.include <bsd.own.mk>
PROG= lint1
SRCS= cgram.y \
- ckbool.c ckctype.c ckgetopt.c debug.c \
+ ckbool.c ckctype.c ckgetopt.c cksnprintb.c debug.c \
decl.c emit.c emit1.c err.c func.c init.c inittyp.c lex.c \
main1.c mem.c mem1.c oper.c scan.l tree.c tyname.c
Index: src/usr.bin/xlint/lint1/err.c
diff -u src/usr.bin/xlint/lint1/err.c:1.225 src/usr.bin/xlint/lint1/err.c:1.226
--- src/usr.bin/xlint/lint1/err.c:1.225 Tue Feb 6 22:47:21 2024
+++ src/usr.bin/xlint/lint1/err.c Fri Mar 1 19:39:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: err.c,v 1.225 2024/02/06 22:47:21 rillig Exp $ */
+/* $NetBSD: err.c,v 1.226 2024/03/01 19:39:28 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: err.c,v 1.225 2024/02/06 22:47:21 rillig Exp $");
+__RCSID("$NetBSD: err.c,v 1.226 2024/03/01 19:39:28 rillig Exp $");
#endif
#include <limits.h>
@@ -412,6 +412,25 @@ static const char *const msgs[] = {
"'_Static_assert' requires C11 or later", // 354
"'_Static_assert' without message requires C23 or later", // 355
"short octal escape '%.*s' followed by digit '%c'", // 356
+ "hex escape '%.*s' mixes uppercase and lowercase digits", // 357
+ "hex escape '%.*s' has more than 2 digits", // 358
+ "missing new-style '\\177' or old-style number base", // 359
+ "missing new-style number base after '\\177'", // 360
+ "number base '%.*s' is %ju, should be 8, 10 or 16", // 361
+ "old-style format contains '\\0'", // 362
+ "non-printing character '%.*s' in description '%.*s'", // 363
+ "missing bit position after '%.*s'", // 364
+ "missing field width after '%.*s'", // 365
+ "missing '\\0' at the end of '%.*s'", // 366
+ "empty description in '%.*s'", // 367
+ "missing comparison value after directive '%.*s'", // 368
+ "bit position '%.*s' in '%.*s' should be escaped as octal or hex", // 369
+ "field width '%.*s' in '%.*s' should be escaped as octal or hex", // 370
+ "bit position '%.*s' (%ju) in '%.*s' out of range %u..%u", // 371
+ "field width '%.*s' (%ju) in '%.*s' out of range 0..%u", // 372
+ "bit field end %ju in '%.*s' out of range 0..64", // 373
+ "unknown directive '%.*s'", // 374
+ "comparison value '%.*s' (%ju) exceeds field width %ju", // 375
};
static bool is_suppressed[sizeof(msgs) / sizeof(msgs[0])];
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.216 src/usr.bin/xlint/lint1/externs1.h:1.217
--- src/usr.bin/xlint/lint1/externs1.h:1.216 Mon Feb 5 23:11:22 2024
+++ src/usr.bin/xlint/lint1/externs1.h Fri Mar 1 19:39:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.216 2024/02/05 23:11:22 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.217 2024/03/01 19:39:28 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -419,3 +419,6 @@ void check_getopt_begin_switch(void);
void check_getopt_case_label(int64_t);
void check_getopt_end_switch(void);
void check_getopt_end_while(void);
+
+/* cksnprintb.c */
+void check_snprintb(const tnode_t *);
Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.605 src/usr.bin/xlint/lint1/tree.c:1.606
--- src/usr.bin/xlint/lint1/tree.c:1.605 Thu Feb 8 20:59:19 2024
+++ src/usr.bin/xlint/lint1/tree.c Fri Mar 1 19:39:28 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.605 2024/02/08 20:59:19 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.606 2024/03/01 19:39:28 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.605 2024/02/08 20:59:19 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.606 2024/03/01 19:39:28 rillig Exp $");
#endif
#include <float.h>
@@ -4444,6 +4444,7 @@ check_expr_call(const tnode_t *tn, const
lint_assert(ln->tn_left->tn_op == NAME);
if (!szof && !is_compiler_builtin(ln->tn_left->tn_sym->s_name))
outcall(tn, vctx || cond, retval_discarded);
+ check_snprintb(tn);
}
static void
Added files:
Index: src/tests/usr.bin/xlint/lint1/msg_357.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_357.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_357.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,50 @@
+/* $NetBSD: msg_357.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_357.c"
+
+// Test for message: hex escape '%.*s' mixes uppercase and lowercase digits [357]
+
+/*
+ * In the format argument of the snprintb and snprintb_m functions, a bit
+ * position or field width is written as an octal or hexadecimal escape
+ * sequence. If the description that follows starts with hex digits (A-Fa-f),
+ * these digits are still part of the escape sequence instead of the
+ * description.
+ *
+ * Since the escape sequences are typically written in lowercase and the
+ * descriptions are typically written in uppercase, a mixture of both cases
+ * indicates a mismatch.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+examples(unsigned u32, uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+5: warning: hex escape '\x0aB' mixes uppercase and lowercase digits [357] */
+ /* expect+4: warning: hex escape '\x0aB' has more than 2 digits [358] */
+ /* expect+3: warning: bit position '\x0aB' (171) in '\x0aBIT' out of range 1..32 [371] */
+ snprintb(buf, sizeof(buf),
+ "\020\x0aBIT",
+ u32);
+
+ // This mismatch goes undetected as it has only 2 digits, does not mix
+ // case and is in bounds. A spellchecker could mark the unknown word
+ // 'ield' to give a hint.
+ snprintb(buf, sizeof(buf),
+ "\020\x1FIELD",
+ u32);
+
+ /* expect+5: warning: hex escape '\x0aB' mixes uppercase and lowercase digits [357] */
+ /* expect+4: warning: hex escape '\x0aB' has more than 2 digits [358] */
+ /* expect+3: warning: bit position '\x0aB' (171) in 'b\x0aBIT\0' out of range 0..63 [371] */
+ snprintb(buf, sizeof(buf),
+ "\177\020b\x0aBIT\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_358.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_358.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_358.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,52 @@
+/* $NetBSD: msg_358.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_358.c"
+
+// Test for message: hex escape '%.*s' has more than 2 digits [358]
+
+/*
+ * In the format argument of the snprintb and snprintb_m functions, a bit
+ * position or field width is written as an octal or hexadecimal escape
+ * sequence. If the description that follows starts with hex digits (A-Fa-f),
+ * these digits are still part of the escape sequence instead of the
+ * description.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+examples(unsigned u32, uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+3: warning: hex escape '\x01B' has more than 2 digits [358] */
+ snprintb(buf, sizeof(buf),
+ "\020\x01BIT",
+ u32);
+
+ /* expect+3: warning: hex escape '\x01b' has more than 2 digits [358] */
+ snprintb(buf, sizeof(buf),
+ "\020\x01bit",
+ u32);
+
+ // This mismatch goes undetected as it has only 2 digits, does not mix
+ // case and is in bounds. A spellchecker could mark the unknown word
+ // 'ield' to give a hint.
+ snprintb(buf, sizeof(buf),
+ "\020\x1FIELD",
+ u32);
+
+ /* expect+3: warning: hex escape '\x01b' has more than 2 digits [358] */
+ snprintb(buf, sizeof(buf),
+ "\177\020b\x01bit\0",
+ u64);
+
+ /* expect+3: warning: hex escape '\x02b' has more than 2 digits [358] */
+ snprintb(buf, sizeof(buf),
+ "\177\020f\x00\x02bit\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_359.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_359.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_359.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,27 @@
+/* $NetBSD: msg_359.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_359.c"
+
+// Test for message: missing new-style '\177' or old-style number base [359]
+
+/*
+ * The first or second character of the snprintb format specifies the number
+ * base. It must be given in binary.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+old_style_number_base(void)
+{
+ char buf[64];
+
+ /* expect+1: warning: missing new-style '\177' or old-style number base [359] */
+ snprintb(buf, sizeof(buf), "", 0);
+ snprintb(buf, sizeof(buf), "\010", 0);
+ snprintb(buf, sizeof(buf), "" "\177\020" "", 0);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_360.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_360.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_360.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,28 @@
+/* $NetBSD: msg_360.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_360.c"
+
+// Test for message: missing new-style number base after '\177' [360]
+
+/*
+ * The new-style format requires the number base as the second character.
+ * This check is merely a byproduct of the implementation, it does not provide
+ * much value on its own.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+new_style_number_base(void)
+{
+ char buf[64];
+
+ /* expect+1: warning: missing new-style number base after '\177' [360] */
+ snprintb(buf, sizeof(buf), "\177", 0);
+ /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "\177\002", 0);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_361.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_361.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_361.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,52 @@
+/* $NetBSD: msg_361.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_361.c"
+
+// Test for message: number base '%.*s' is %ju, should be 8, 10 or 16 [361]
+
+/*
+ * The first or second character of the snprintb format specifies the number
+ * base. It must be given in binary.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+old_style_number_base(void)
+{
+ char buf[64];
+
+ /* expect+1: warning: missing new-style '\177' or old-style number base [359] */
+ snprintb(buf, sizeof(buf), "", 0);
+ /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "\002", 0);
+ snprintb(buf, sizeof(buf), "\010", 0);
+ snprintb(buf, sizeof(buf), "\n", 0);
+ snprintb(buf, sizeof(buf), "\020", 0);
+ /* expect+1: warning: number base '\014' is 12, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "" "\014" "", 0);
+ snprintb(buf, sizeof(buf), "" "\020" "", 0);
+}
+
+void
+new_style_number_base(void)
+{
+ char buf[64];
+
+ /* expect+1: warning: missing new-style number base after '\177' [360] */
+ snprintb(buf, sizeof(buf), "\177", 0);
+ /* expect+1: warning: number base '\0' is 0, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "\177\0", 0);
+ /* expect+1: warning: number base '\002' is 2, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "\177\002", 0);
+ snprintb(buf, sizeof(buf), "\177\010", 0);
+ snprintb(buf, sizeof(buf), "\177\n", 0);
+ snprintb(buf, sizeof(buf), "\177\020", 0);
+ /* expect+1: warning: number base '\014' is 12, should be 8, 10 or 16 [361] */
+ snprintb(buf, sizeof(buf), "" "\177\014" "", 0);
+ snprintb(buf, sizeof(buf), "" "\177\020" "", 0);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_362.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_362.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_362.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,28 @@
+/* $NetBSD: msg_362.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_362.c"
+
+// Test for message: old-style format contains '\0' [362]
+
+/*
+ * The old-style format uses 1-based bit positions, from 1 up to 32.
+ * A null character would prematurely end the format argument.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+1: warning: bit position '\000' (0) in '\000lsb' out of range 1..32 [371] */
+ snprintb(buf, sizeof(buf), "\020\000lsb\037msb", u32);
+ /* expect+2: warning: old-style format contains '\0' [362] */
+ /* expect+1: warning: bit position '\000' (0) in '\000lsb' out of range 1..32 [371] */
+ snprintb(buf, sizeof(buf), "\020\037msb\000lsb", u32);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_363.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_363.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_363.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,41 @@
+/* $NetBSD: msg_363.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_363.c"
+
+// Test for message: non-printing character '%.*s' in description '%.*s' [363]
+
+/*
+ * The purpose of snprintb is to produce a printable, visible representation
+ * of a binary number, therefore the description should consist of visible
+ * characters only.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+old_style_description(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+6: warning: bit position '\t' in '\tprint' should be escaped as octal or hex [369] */
+ /* expect+5: warning: non-printing character '\377' in description 'able\377' [363] */
+ /* expect+4: warning: bit position '\n' in '\nable\377' should be escaped as octal or hex [369] */
+ snprintb(buf, sizeof(buf),
+ "\020"
+ "\001non\tprint\nable\377",
+ u32);
+
+ /* expect+8: warning: old-style format contains '\0' [362] */
+ /* expect+7: warning: bit position '\000' (0) in '\000print' out of range 1..32 [371] */
+ /* expect+6: warning: old-style format contains '\0' [362] */
+ /* expect+5: warning: bit position '\n' in '\nable' should be escaped as octal or hex [369] */
+ /* expect+4: warning: empty description in '\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\020"
+ "\001non\000print\nable\0",
+ u32);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_364.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_364.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_364.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,34 @@
+/* $NetBSD: msg_364.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_364.c"
+
+// Test for message: missing bit position after '%.*s' [364]
+
+/*
+ * The directives 'b', 'f' and 'F' require a bit position as their first
+ * argument.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+4: warning: missing bit position after 'b' [364] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of 'b\007' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b\007",
+ u32);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_365.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_365.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_365.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,33 @@
+/* $NetBSD: msg_365.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_365.c"
+
+// Test for message: missing field width after '%.*s' [365]
+
+/*
+ * The directives 'f' and 'F' require a field width as their second argument.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+4: warning: missing field width after 'f\000' [365] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\000",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of 'f\007\010' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\007\010",
+ u32);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_366.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_366.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_366.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,68 @@
+/* $NetBSD: msg_366.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_366.c"
+
+// Test for message: missing '\0' at the end of '%.*s' [366]
+
+/*
+ * In the new-style format, each directive ends with a '\0'. If that's not
+ * the case, snprintb will read beyond the end of the format argument, looking
+ * for the terminating '\0'. In the most common case where the format comes
+ * from a string literal, the '\0' from the directive needs to be spelled out,
+ * while the '\0' that terminates the sequence of directives is provided by
+ * the C compiler.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+4: warning: unknown directive '\0' [374] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "\0",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of 'b\007' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b\007",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of 'f\007\000' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\007\000",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of 'F\007\000' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "F\007\000",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of '=\007value' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "=\007value",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of ':\007value' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ ":\007value",
+ u32);
+
+ /* expect+4: warning: missing '\0' at the end of '*default' [366] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "*default",
+ u32);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_367.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_367.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_367.c Fri Mar 1 19:39:28 2024
@@ -0,0 +1,62 @@
+/* $NetBSD: msg_367.c,v 1.1 2024/03/01 19:39:28 rillig Exp $ */
+# 3 "msg_367.c"
+
+// Test for message: empty description in '%.*s' [367]
+
+/*
+ * Each bit or field or comparison value gets a description. If such a
+ * description is empty, the generated output will contain empty angle
+ * brackets or multiple adjacent commas or commas adjacent to an angle
+ * bracket, such as '<,,,,>'.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32)
+{
+ char buf[64];
+
+ /* expect+4: warning: empty description in 'b\000\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b\000\0",
+ u32);
+
+ /* expect+4: warning: empty description in 'f\000\010\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\000\010\0",
+ u32);
+
+ // No warning, as 'F' does not take a description.
+ // If there were a description, it would simply be skipped.
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "F\000\010\0",
+ u32);
+
+ /* expect+4: warning: empty description in '=\000\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "=\000\0",
+ u32);
+
+ /* expect+4: warning: empty description in ':\000\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ ":\000\0",
+ u32);
+
+ /* expect+4: warning: empty description in '*\0' [367] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "*\0",
+ u32);
+
+}
Index: src/tests/usr.bin/xlint/lint1/msg_368.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_368.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_368.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,34 @@
+/* $NetBSD: msg_368.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_368.c"
+
+// Test for message: missing comparison value after directive '%.*s' [368]
+
+/*
+ * The directives '=' and ':' require a comparison value as their argument,
+ * followed by the description and the terminating null character.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t val)
+{
+ char buf[64];
+
+ /* expect+4: warning: missing comparison value after directive '=' [368] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "=",
+ val);
+
+ /* expect+4: warning: missing comparison value after directive ':' [368] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ ":",
+ val);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_369.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_369.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_369.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,52 @@
+/* $NetBSD: msg_369.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_369.c"
+
+// Test for message: bit position '%.*s' in '%.*s' should be escaped as octal or hex [369]
+
+/*
+ * To distinguish bit positions from the description text, they should use
+ * octal or hex escape sequences. Of these, octal escape sequences are less
+ * error-prone, as they consist of at most 3 octal digits, whereas hex escape
+ * sequences consume as many digits as available.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32, uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+8: warning: bit position ' ' in ' space' should be escaped as octal or hex [369] */
+ /* expect+7: warning: bit position '\t' in '\ttab' should be escaped as octal or hex [369] */
+ /* expect+6: warning: bit position '\n' in '\nnewline' should be escaped as octal or hex [369] */
+ snprintb(buf, sizeof(buf),
+ "\020"
+ " space"
+ "\ttab"
+ "\nnewline",
+ u32);
+
+ /* expect+8: warning: bit position ' ' in 'b space\0' should be escaped as octal or hex [369] */
+ /* expect+7: warning: bit position '\t' in 'b\ttab\0' should be escaped as octal or hex [369] */
+ /* expect+6: warning: bit position '\n' in 'b\nnewline\0' should be escaped as octal or hex [369] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b space\0"
+ "b\ttab\0"
+ "b\nnewline\0",
+ u64);
+
+ /* expect+6: warning: bit position '\t' in 'f\t\010tab\0' should be escaped as octal or hex [369] */
+ /* expect+5: warning: bit position '\n' in 'F\n\010newline\0' should be escaped as octal or hex [369] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\t\010tab\0"
+ "F\n\010newline\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_370.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_370.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_370.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,50 @@
+/* $NetBSD: msg_370.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_370.c"
+
+// Test for message: field width '%.*s' in '%.*s' should be escaped as octal or hex [370]
+
+/*
+ * To distinguish field widths from the description text, they should use
+ * octal or hex escape sequences. Of these, octal escape sequences are less
+ * error-prone, as they consist of at most 3 octal digits, whereas hex escape
+ * sequences consume as many digits as available.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+11: warning: bit position ' ' in 'f space\0' should be escaped as octal or hex [369] */
+ /* expect+10: warning: field width ' ' in 'f space\0' should be escaped as octal or hex [370] */
+ /* expect+9: warning: bit position '\t' in 'f\t\ttab\0' should be escaped as octal or hex [369] */
+ /* expect+8: warning: field width '\t' in 'f\t\ttab\0' should be escaped as octal or hex [370] */
+ /* expect+7: warning: bit position '\n' in 'f\n\nnewline\0' should be escaped as octal or hex [369] */
+ /* expect+6: warning: field width '\n' in 'f\n\nnewline\0' should be escaped as octal or hex [370] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f space\0"
+ "f\t\ttab\0"
+ "f\n\nnewline\0",
+ u64);
+
+ /* expect+11: warning: bit position ' ' in 'F space\0' should be escaped as octal or hex [369] */
+ /* expect+10: warning: field width ' ' in 'F space\0' should be escaped as octal or hex [370] */
+ /* expect+9: warning: bit position '\t' in 'F\t\ttab\0' should be escaped as octal or hex [369] */
+ /* expect+8: warning: field width '\t' in 'F\t\ttab\0' should be escaped as octal or hex [370] */
+ /* expect+7: warning: bit position '\n' in 'F\n\nnewline\0' should be escaped as octal or hex [369] */
+ /* expect+6: warning: field width '\n' in 'F\n\nnewline\0' should be escaped as octal or hex [370] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "F space\0"
+ "F\t\ttab\0"
+ "F\n\nnewline\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_371.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_371.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_371.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,61 @@
+/* $NetBSD: msg_371.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_371.c"
+
+// Test for message: bit position '%.*s' (%ju) in '%.*s' out of range %u..%u [371]
+
+/*
+ * In old-style formats, bit positions are 1-based and must be in the range
+ * from 1 to 32. In new-style formats, bit positions are 0-based and must be
+ * in the range from 0 to 63.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(unsigned u32, uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+11: warning: bit position '\000' (0) in '\000zero' out of range 1..32 [371] */
+ /* expect+10: warning: non-printing character '\177' in description 'bit32""\041bit33""\177' [363] */
+ /* expect+9: warning: non-printing character '\377' in description 'bit32""\041bit33""\177bit127""\377' [363] */
+ snprintb(buf, sizeof(buf),
+ "\020"
+ "\000zero"
+ "\001bit1"
+ "\040bit32"
+ "\041bit33"
+ "\177bit127"
+ "\377bit255",
+ u32);
+
+ /* expect+10: warning: bit position '\100' (64) in 'b\100bit64\0' out of range 0..63 [371] */
+ /* expect+9: warning: bit position '\177' (127) in 'b\177bit127\0' out of range 0..63 [371] */
+ /* expect+8: warning: bit position '\377' (255) in 'b\377bit255\0' out of range 0..63 [371] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "b\000bit0\0"
+ "b\077bit63\0"
+ "b\100bit64\0"
+ "b\177bit127\0"
+ "b\377bit255\0",
+ u64);
+
+ /* expect+11: warning: bit position '\100' (64) in 'F\100\000none\0' out of range 0..63 [371] */
+ /* expect+10: warning: bit position '\100' (64) in 'f\100\001oob\0' out of range 0..63 [371] */
+ /* expect+9: warning: bit field end 65 in 'f\100\001oob\0' out of range 0..64 [373] */
+ /* expect+8: warning: bit position '\101' (65) in 'F\101\001oob\0' out of range 0..63 [371] */
+ /* expect+7: warning: bit field end 66 in 'F\101\001oob\0' out of range 0..64 [373] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\077\001msb\0"
+ "F\100\000none\0"
+ "f\100\001oob\0"
+ "F\101\001oob\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_372.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_372.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_372.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,35 @@
+/* $NetBSD: msg_372.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_372.c"
+
+// Test for message: field width '%.*s' (%ju) in '%.*s' out of range 0..%u [372]
+
+/*
+ * In new-style formats, the width of a bit-field must be between 0 (an empty
+ * bit-field) and 64 (a bit-field spanning the whole value).
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+11: warning: field width '\101' (65) in 'f\000\101all+1\0' out of range 0..64 [372] */
+ /* expect+10: warning: bit field end 65 in 'f\000\101all+1\0' out of range 0..64 [373] */
+ /* expect+9: warning: bit field end 65 in 'f\001\100oob64\0' out of range 0..64 [373] */
+ /* expect+8: warning: field width '\377' (255) in 'f\010\377oob64\0' out of range 0..64 [372] */
+ /* expect+7: warning: bit field end 263 in 'f\010\377oob64\0' out of range 0..64 [373] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\000\100all\0"
+ "f\000\101all+1\0"
+ "f\001\100oob64\0"
+ "f\010\377oob64\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_373.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_373.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_373.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,36 @@
+/* $NetBSD: msg_373.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_373.c"
+
+// Test for message: bit field end %ju in '%.*s' out of range 0..64 [373]
+
+/*
+ * A bit-field may start in the middle of the value. When its end goes beyond
+ * 64, this means the uppermost bits will always be 0, and a narrower
+ * bit-field would have the same effect.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+11: warning: field width '\101' (65) in 'f\000\101all+1\0' out of range 0..64 [372] */
+ /* expect+10: warning: bit field end 65 in 'f\000\101all+1\0' out of range 0..64 [373] */
+ /* expect+9: warning: bit field end 65 in 'f\001\100oob64\0' out of range 0..64 [373] */
+ /* expect+8: warning: field width '\377' (255) in 'f\010\377oob64\0' out of range 0..64 [372] */
+ /* expect+7: warning: bit field end 263 in 'f\010\377oob64\0' out of range 0..64 [373] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\000\100all\0"
+ "f\000\101all+1\0"
+ "f\001\100oob64\0"
+ "f\010\377oob64\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_374.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_374.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_374.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,34 @@
+/* $NetBSD: msg_374.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_374.c"
+
+// Test for message: unknown directive '%.*s' [374]
+
+/*
+ * In the new-style format, an unknown directive is assumed to have a single
+ * argument, followed by a null-terminated description.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+4: warning: unknown directive 'x' [374] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "x12345\0",
+ u64);
+
+ /* expect+4: warning: unknown directive '\000' [374] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "\00012345\0",
+ u64);
+}
Index: src/tests/usr.bin/xlint/lint1/msg_375.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_375.c:1.1
--- /dev/null Fri Mar 1 19:39:29 2024
+++ src/tests/usr.bin/xlint/lint1/msg_375.c Fri Mar 1 19:39:29 2024
@@ -0,0 +1,38 @@
+/* $NetBSD: msg_375.c,v 1.1 2024/03/01 19:39:29 rillig Exp $ */
+# 3 "msg_375.c"
+
+// Test for message: comparison value '%.*s' (%ju) exceeds field width %ju [375]
+
+/*
+ * When a bit field can take the values 0 to 15, there is no point comparing
+ * it to 16.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+typedef typeof(sizeof(0)) size_t;
+typedef unsigned long long uint64_t;
+
+int snprintb(char*, size_t, const char*, uint64_t);
+
+void
+example(uint64_t u64)
+{
+ char buf[64];
+
+ /* expect+14: warning: comparison value '\020' (16) exceeds field width 4 [375] */
+ /* expect+13: warning: comparison value '\377' (255) exceeds field width 4 [375] */
+ /* expect+12: warning: comparison value '\020' (16) exceeds field width 4 [375] */
+ /* expect+11: warning: comparison value '\377' (255) exceeds field width 4 [375] */
+ snprintb(buf, sizeof(buf),
+ "\177\020"
+ "f\000\004low\0"
+ "=\01715\0"
+ "=\02016\0"
+ "=\37716\0"
+ "F\000\004low\0"
+ ":\01715\0"
+ ":\02016\0"
+ ":\37716\0",
+ u64);
+}