Module Name:    src
Committed By:   rillig
Date:           Sun Dec  8 17:12:01 UTC 2024

Modified Files:
        src/distrib/sets/lists/tests: mi
        src/tests/usr.bin/xlint/lint1: msg_255.c t_usage.sh
        src/usr.bin/xlint/common: externs.h tyname.c
        src/usr.bin/xlint/lint1: err.c externs1.h lex.c scan.l
        src/usr.bin/xlint/xlint: xlint.c
Added Files:
        src/tests/usr.bin/xlint/lint1: msg_385.c

Log Message:
lint: warn about do-while macros that end with a semicolon


To generate a diff of this commit:
cvs rdiff -u -r1.1348 -r1.1349 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.6 -r1.7 src/tests/usr.bin/xlint/lint1/msg_255.c
cvs rdiff -u -r0 -r1.1 src/tests/usr.bin/xlint/lint1/msg_385.c
cvs rdiff -u -r1.26 -r1.27 src/tests/usr.bin/xlint/lint1/t_usage.sh
cvs rdiff -u -r1.36 -r1.37 src/usr.bin/xlint/common/externs.h
cvs rdiff -u -r1.64 -r1.65 src/usr.bin/xlint/common/tyname.c
cvs rdiff -u -r1.259 -r1.260 src/usr.bin/xlint/lint1/err.c
cvs rdiff -u -r1.237 -r1.238 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.231 -r1.232 src/usr.bin/xlint/lint1/lex.c
cvs rdiff -u -r1.142 -r1.143 src/usr.bin/xlint/lint1/scan.l
cvs rdiff -u -r1.125 -r1.126 src/usr.bin/xlint/xlint/xlint.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.1348 src/distrib/sets/lists/tests/mi:1.1349
--- src/distrib/sets/lists/tests/mi:1.1348	Sun Dec  1 18:37:53 2024
+++ src/distrib/sets/lists/tests/mi	Sun Dec  8 17:12:00 2024
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1348 2024/12/01 18:37:53 rillig Exp $
+# $NetBSD: mi,v 1.1349 2024/12/08 17:12:00 rillig Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -7591,6 +7591,7 @@
 ./usr/tests/usr.bin/xlint/lint1/msg_382.c			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/xlint/lint1/msg_383.c			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/xlint/lint1/msg_384.c			tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/xlint/lint1/msg_385.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/msg_255.c
diff -u src/tests/usr.bin/xlint/lint1/msg_255.c:1.6 src/tests/usr.bin/xlint/lint1/msg_255.c:1.7
--- src/tests/usr.bin/xlint/lint1/msg_255.c:1.6	Fri Aug 11 04:27:49 2023
+++ src/tests/usr.bin/xlint/lint1/msg_255.c	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: msg_255.c,v 1.6 2023/08/11 04:27:49 rillig Exp $	*/
+/*	$NetBSD: msg_255.c,v 1.7 2024/12/08 17:12:01 rillig Exp $	*/
 # 3 "msg_255.c"
 
 // Test for message: undefined or invalid '#' directive [255]
@@ -34,12 +34,13 @@
 /* expect+1: warning: undefined or invalid '#' directive [255] */
 # 4 /
 
-/* expect+1: warning: undefined or invalid '#' directive [255] */
+/* expect+3: error: newline in string or char constant [254] */
+/* expect+2: error: unterminated string constant [258] */
 # 5 "unfinished
 
 // An empty string means standard input; tabs may be used for spacing.
 #	6	""
 
-# 44 "msg_255.c"
+# 45 "msg_255.c"
 
 int dummy;

Index: src/tests/usr.bin/xlint/lint1/t_usage.sh
diff -u src/tests/usr.bin/xlint/lint1/t_usage.sh:1.26 src/tests/usr.bin/xlint/lint1/t_usage.sh:1.27
--- src/tests/usr.bin/xlint/lint1/t_usage.sh:1.26	Sun Dec  1 18:37:54 2024
+++ src/tests/usr.bin/xlint/lint1/t_usage.sh	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-# $NetBSD: t_usage.sh,v 1.26 2024/12/01 18:37:54 rillig Exp $
+# $NetBSD: t_usage.sh,v 1.27 2024/12/08 17:12:01 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 384 code.c /dev/null
+	    "$lint1" -X 385 code.c /dev/null
 
 	# Larger than the largest known message.
 	atf_check \
 	    -s 'exit:1' \
-	    -e "inline:lint1: invalid message ID '385'\n" \
-	    "$lint1" -X 385 code.c /dev/null
+	    -e "inline:lint1: invalid message ID '386'\n" \
+	    "$lint1" -X 386 code.c /dev/null
 
 	# Whitespace is not allowed before a message ID.
 	atf_check \

Index: src/usr.bin/xlint/common/externs.h
diff -u src/usr.bin/xlint/common/externs.h:1.36 src/usr.bin/xlint/common/externs.h:1.37
--- src/usr.bin/xlint/common/externs.h:1.36	Fri Feb  2 16:25:58 2024
+++ src/usr.bin/xlint/common/externs.h	Sun Dec  8 17:12:00 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: externs.h,v 1.36 2024/02/02 16:25:58 rillig Exp $	*/
+/*	$NetBSD: externs.h,v 1.37 2024/12/08 17:12:00 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -41,6 +41,7 @@ const char *tspec_name(tspec_t);
 #if IS_LINT1
 void buf_init(buffer *);
 void buf_add_char(buffer *, char);
+void buf_add(buffer *, const char *);
 #endif
 
 /*

Index: src/usr.bin/xlint/common/tyname.c
diff -u src/usr.bin/xlint/common/tyname.c:1.64 src/usr.bin/xlint/common/tyname.c:1.65
--- src/usr.bin/xlint/common/tyname.c:1.64	Sat Nov 30 16:34:26 2024
+++ src/usr.bin/xlint/common/tyname.c	Sun Dec  8 17:12:00 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: tyname.c,v 1.64 2024/11/30 16:34:26 rillig Exp $	*/
+/*	$NetBSD: tyname.c,v 1.65 2024/12/08 17:12:00 rillig Exp $	*/
 
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: tyname.c,v 1.64 2024/11/30 16:34:26 rillig Exp $");
+__RCSID("$NetBSD: tyname.c,v 1.65 2024/12/08 17:12:00 rillig Exp $");
 #endif
 
 #include <assert.h>
@@ -94,11 +94,10 @@ intern(const char *name)
 	return n->ntn_name;
 }
 
-#if IS_LINT1
-void
-#else
-static void
+#if !IS_LINT1
+static
 #endif
+void
 buf_init(buffer *buf)
 {
 	buf->len = 0;
@@ -134,7 +133,10 @@ buf_add_char(buffer *buf, char c)
 }
 #endif
 
-static void
+#if !IS_LINT1
+static
+#endif
+void
 buf_add(buffer *buf, const char *s)
 {
 	buf_add_mem(buf, s, strlen(s));

Index: src/usr.bin/xlint/lint1/err.c
diff -u src/usr.bin/xlint/lint1/err.c:1.259 src/usr.bin/xlint/lint1/err.c:1.260
--- src/usr.bin/xlint/lint1/err.c:1.259	Sun Dec  1 18:37:54 2024
+++ src/usr.bin/xlint/lint1/err.c	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: err.c,v 1.259 2024/12/01 18:37:54 rillig Exp $	*/
+/*	$NetBSD: err.c,v 1.260 2024/12/08 17:12:01 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.259 2024/12/01 18:37:54 rillig Exp $");
+__RCSID("$NetBSD: err.c,v 1.260 2024/12/08 17:12:01 rillig Exp $");
 #endif
 
 #include <limits.h>
@@ -440,6 +440,7 @@ static const char *const msgs[] = {
 	"constant assignment of type '%s' in operand of '!' always evaluates to '%s'", 	// 382
 	"passing '%s' to argument %d discards '%s'",			// 383
 	"function definition with identifier list is obsolete in C23",	// 384
+	"do-while macro '%.*s' ends with semicolon",			// 385
 };
 
 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.237 src/usr.bin/xlint/lint1/externs1.h:1.238
--- src/usr.bin/xlint/lint1/externs1.h:1.237	Sat Nov 30 10:43:49 2024
+++ src/usr.bin/xlint/lint1/externs1.h	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: externs1.h,v 1.237 2024/11/30 10:43:49 rillig Exp $	*/
+/*	$NetBSD: externs1.h,v 1.238 2024/12/08 17:12:01 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -391,6 +391,15 @@ void outusg(const sym_t *);
 /*
  * lex.c
  */
+void lex_pp_begin(void);
+void lex_pp_identifier(const char *);
+void lex_pp_number(const char *);
+void lex_pp_character_constant(void);
+void lex_pp_string_literal(void);
+void lex_pp_punctuator(const char *);
+void lex_pp_comment(void);
+void lex_pp_whitespace(void);
+void lex_pp_end(void);
 int lex_name(const char *, size_t);
 int lex_integer_constant(const char *, size_t, int);
 int lex_floating_constant(const char *, size_t);
@@ -399,7 +408,6 @@ int lex_string(void);
 int lex_wide_string(void);
 int lex_character_constant(void);
 int lex_wide_character_constant(void);
-void lex_directive(const char *);
 void lex_next_line(void);
 void lex_comment(void);
 void lex_slash_slash_comment(void);

Index: src/usr.bin/xlint/lint1/lex.c
diff -u src/usr.bin/xlint/lint1/lex.c:1.231 src/usr.bin/xlint/lint1/lex.c:1.232
--- src/usr.bin/xlint/lint1/lex.c:1.231	Fri Nov 29 20:02:35 2024
+++ src/usr.bin/xlint/lint1/lex.c	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: lex.c,v 1.231 2024/11/29 20:02:35 rillig Exp $ */
+/* $NetBSD: lex.c,v 1.232 2024/12/08 17:12:01 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: lex.c,v 1.231 2024/11/29 20:02:35 rillig Exp $");
+__RCSID("$NetBSD: lex.c,v 1.232 2024/12/08 17:12:01 rillig Exp $");
 #endif
 
 #include <ctype.h>
@@ -689,20 +689,20 @@ lex_operator(int t, op_t o)
 	return t;
 }
 
-static buffer *
+static buffer
 read_quoted(bool *complete, char delim, bool wide)
 {
-	buffer *buf = xcalloc(1, sizeof(*buf));
-	buf_init(buf);
+	buffer buf;
+	buf_init(&buf);
 	if (wide)
-		buf_add_char(buf, 'L');
-	buf_add_char(buf, delim);
+		buf_add_char(&buf, 'L');
+	buf_add_char(&buf, delim);
 
 	for (;;) {
 		int c = read_byte();
 		if (c <= 0)
 			break;
-		buf_add_char(buf, (char)c);
+		buf_add_char(&buf, (char)c);
 		if (c == '\n')
 			break;
 		if (c == delim) {
@@ -711,13 +711,13 @@ read_quoted(bool *complete, char delim, 
 		}
 		if (c == '\\') {
 			c = read_byte();
-			buf_add_char(buf, (char)(c <= 0 ? ' ' : c));
+			buf_add_char(&buf, (char)(c <= 0 ? ' ' : c));
 			if (c <= 0)
 				break;
 		}
 	}
 	*complete = false;
-	buf_add_char(buf, delim);
+	buf_add_char(&buf, delim);
 	return buf;
 }
 
@@ -931,12 +931,12 @@ check_quoted(const buffer *buf, bool com
 		error(253);
 }
 
-static buffer *
+static buffer
 lex_quoted(char delim, bool wide)
 {
 	bool complete;
-	buffer *buf = read_quoted(&complete, delim, wide);
-	check_quoted(buf, complete, delim);
+	buffer buf = read_quoted(&complete, delim, wide);
+	check_quoted(&buf, complete, delim);
 	return buf;
 }
 
@@ -944,12 +944,12 @@ lex_quoted(char delim, bool wide)
 int
 lex_character_constant(void)
 {
-	buffer *buf = lex_quoted('\'', false);
+	buffer buf = lex_quoted('\'', false);
 
 	size_t n = 0;
 	uint64_t val = 0;
 	quoted_iterator it = { .end = 0 };
-	while (quoted_next(buf, &it)) {
+	while (quoted_next(&buf, &it)) {
 		val = (val << CHAR_SIZE) + it.value;
 		n++;
 	}
@@ -983,13 +983,13 @@ lex_character_constant(void)
 int
 lex_wide_character_constant(void)
 {
-	buffer *buf = lex_quoted('\'', true);
+	buffer buf = lex_quoted('\'', true);
 
 	static char wbuf[MB_LEN_MAX + 1];
 	size_t n = 0, nmax = MB_CUR_MAX;
 
 	quoted_iterator it = { .end = 0 };
-	while (quoted_next(buf, &it)) {
+	while (quoted_next(&buf, &it)) {
 		if (n < nmax)
 			wbuf[n] = (char)it.value;
 		n++;
@@ -1064,36 +1064,19 @@ set_csrc_pos(void)
 	outsrc(transform_filename(curr_pos.p_file, strlen(curr_pos.p_file)));
 }
 
-/*
- * Called for preprocessor directives. Currently implemented are:
- *	# pragma [argument...]
- *	# lineno
- *	# lineno "filename" [GCC-flag...]
- */
-void
-lex_directive(const char *text)
+/* # lineno ["filename" [GCC-flag...]]  */
+static void
+set_location(const char *p)
 {
-	const char *p = text + 1;	/* skip '#' */
-
-	while (*p == ' ' || *p == '\t')
-		p++;
-
-	if (!ch_isdigit(*p)) {
-		if (strncmp(p, "pragma", 6) == 0
-		    && ch_isspace(p[6]))
-			return;
-		goto error;
-	}
-
 	char *end;
 	long ln = strtol(--p, &end, 10);
 	if (end == p)
 		goto error;
 	p = end;
 
-	if (*p != ' ' && *p != '\t' && *p != '\0')
+	if (*p != ' ' && *p != '\0')
 		goto error;
-	while (*p == ' ' || *p == '\t')
+	while (*p == ' ')
 		p++;
 
 	if (*p != '\0') {
@@ -1132,6 +1115,141 @@ error:
 	warning(255);
 }
 
+static void
+check_stmt_macro(const char *text)
+{
+	const char *p = text;
+	while (*p == ' ')
+		p++;
+
+	const char *name_start = p;
+	while (ch_isalnum(*p) || *p == '_')
+		p++;
+	const char *name_end = p;
+
+	if (*p == '(') {
+		while (*p != '\0' && *p != ')')
+			p++;
+		if (*p == ')')
+			p++;
+	}
+
+	while (*p == ' ')
+		p++;
+
+	if (strncmp(p, "do", 2) == 0 && !ch_isalnum(p[2]))
+		/* do-while macro '%.*s' ends with semicolon */
+		warning(385, (int)(name_end - name_start), name_start);
+}
+
+// Between lex_pp_begin and lex_pp_end, the current preprocessing line,
+// with comments and whitespace converted to a single space.
+static buffer pp_line;
+
+void
+lex_pp_begin(void)
+{
+	if (pp_line.data == NULL)
+		buf_init(&pp_line);
+	debug_step("%s", __func__);
+	lint_assert(pp_line.len == 0);
+}
+
+void
+lex_pp_identifier(const char *text)
+{
+	debug_step("%s '%s'", __func__, text);
+	buf_add(&pp_line, text);
+}
+
+void
+lex_pp_number(const char *text)
+{
+	debug_step("%s '%s'", __func__, text);
+	buf_add(&pp_line, text);
+}
+
+void
+lex_pp_character_constant(void)
+{
+	buffer buf = lex_quoted('\'', false);
+	debug_step("%s '%s'", __func__, buf.data);
+	buf_add(&pp_line, buf.data);
+	free(buf.data);
+}
+
+void
+lex_pp_string_literal(void)
+{
+	buffer buf = lex_quoted('"', false);
+	debug_step("%s '%s'", __func__, buf.data);
+	buf_add(&pp_line, buf.data);
+	free(buf.data);
+}
+
+void
+lex_pp_punctuator(const char *text)
+{
+	debug_step("%s '%s'", __func__, text);
+	buf_add(&pp_line, text);
+}
+
+void
+lex_pp_comment(void)
+{
+	int lc = -1, c;
+
+	for (;;) {
+		if ((c = read_byte()) == EOF) {
+			/* unterminated comment */
+			error(256);
+			return;
+		}
+		if (lc == '*' && c == '/')
+			break;
+		lc = c;
+	}
+
+	buf_add_char(&pp_line, ' ');
+}
+
+void
+lex_pp_whitespace(void)
+{
+	buf_add_char(&pp_line, ' ');
+}
+
+void
+lex_pp_end(void)
+{
+	const char *text = pp_line.data;
+	size_t len = pp_line.len;
+	while (len > 0 && text[len - 1] == ' ')
+		len--;
+	debug_step("%s '%.*s'", __func__, (int)len, text);
+
+	const char *p = text;
+	while (*p == ' ')
+		p++;
+
+	if (ch_isdigit(*p))
+		set_location(p);
+	else if (strncmp(p, "pragma ", 7) == 0)
+		goto done;
+	else if (strncmp(p, "define ", 7) == 0) {
+		 if (text[len - 1] == ';')
+			check_stmt_macro(p + 7);
+	} else if (strncmp(p, "undef ", 6) == 0)
+		goto done;
+	else
+		/* undefined or invalid '#' directive */
+		warning(255);
+
+done:
+	pp_line.len = 0;
+	pp_line.data[0] = '\0';
+}
+
 /* Handle lint comments such as ARGSUSED. */
 void
 lex_comment(void)
@@ -1251,7 +1369,9 @@ reset_suppressions(void)
 int
 lex_string(void)
 {
-	yylval.y_string = lex_quoted('"', false);
+	buffer *buf = xmalloc(sizeof(*buf));
+	*buf = lex_quoted('"', false);
+	yylval.y_string = buf;
 	return T_STRING;
 }
 
@@ -1277,18 +1397,19 @@ wide_length(const buffer *buf)
 int
 lex_wide_string(void)
 {
-	buffer *buf = lex_quoted('"', true);
+	buffer buf = lex_quoted('"', true);
 
 	buffer str;
 	buf_init(&str);
 	quoted_iterator it = { .end = 0 };
-	while (quoted_next(buf, &it))
+	while (quoted_next(&buf, &it))
 		buf_add_char(&str, (char)it.value);
 
-	free(buf->data);
-	*buf = (buffer) { .len = wide_length(&str) };
+	free(buf.data);
 
-	yylval.y_string = buf;
+	buffer *len_buf = xcalloc(1, sizeof(*len_buf));
+	len_buf->len = wide_length(&str);
+	yylval.y_string = len_buf;
 	return T_STRING;
 }
 

Index: src/usr.bin/xlint/lint1/scan.l
diff -u src/usr.bin/xlint/lint1/scan.l:1.142 src/usr.bin/xlint/lint1/scan.l:1.143
--- src/usr.bin/xlint/lint1/scan.l:1.142	Sun May 12 08:48:36 2024
+++ src/usr.bin/xlint/lint1/scan.l	Sun Dec  8 17:12:01 2024
@@ -1,5 +1,5 @@
 %{
-/* $NetBSD: scan.l,v 1.142 2024/05/12 08:48:36 rillig Exp $ */
+/* $NetBSD: scan.l,v 1.143 2024/12/08 17:12:01 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: scan.l,v 1.142 2024/05/12 08:48:36 rillig Exp $");
+__RCSID("$NetBSD: scan.l,v 1.143 2024/12/08 17:12:01 rillig Exp $");
 #endif
 
 #include "lint1.h"
@@ -49,9 +49,20 @@ EXP	([eE][+-]?[0-9]+)
 PEXP	(p[+-]?[0-9A-Fa-f]+)
 FSUF	([fFlL]?[i]?)
 
+punctuator_1	[\[\](){}.]|->
+punctuator_2	{punctuator_1}|\+\+|--|[&*+\-~!]
+punctuator_3	{punctuator_2}|\/|%|<<|>>|<|>|<=|>=|==|!=|\^|\||&&|\|\|
+punctuator_4	{punctuator_3}|\?|:|::|;|\.\.\.
+punctuator_5	{punctuator_4}|=|\*=|\/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=
+punctuator_6	{punctuator_5}|,|#|##
+punctuator_7	{punctuator_6}|<:|:>|<%|%>|%:|%:%:
+punctuator	{punctuator_7}|@
+
 %pointer
 %option nounput
 
+%x preprocessing
+
 %%
 
 [_A-Za-z][_A-Za-z0-9]*		return lex_name(yytext, yyleng);
@@ -115,11 +126,29 @@ FSUF	([fFlL]?[i]?)
 "::"				return T_DCOLON;
 "'"				return lex_character_constant();
 "L'"				return lex_wide_character_constant();
-^#.*$				lex_directive(yytext);
 \n				lex_next_line();
 \t|" "|\f|\v			;
 "/*"				lex_comment();
 "//"				lex_slash_slash_comment();
+
+^#				{
+					BEGIN preprocessing;
+					lex_pp_begin();
+				}
+<preprocessing>[_A-Za-z][_A-Za-z0-9]*	lex_pp_identifier(yytext);
+<preprocessing>\.?[0-9]('?[_A-Za-z0-9]|[EePp][-+][0-9]+|\.)*	lex_pp_number(yytext);
+<preprocessing>\'		lex_pp_character_constant();
+<preprocessing>\"		lex_pp_string_literal();
+<preprocessing>{punctuator}	lex_pp_punctuator(yytext);
+<preprocessing>\/\*		lex_pp_comment();
+<preprocessing>[ \f\t\v]+	lex_pp_whitespace();
+<preprocessing>.		lex_unknown_character(yytext[0]);
+<preprocessing>\n		{
+					lex_pp_end();
+					lex_next_line();
+					BEGIN INITIAL;
+				}
+
 .				lex_unknown_character(yytext[0]);
 
 %%

Index: src/usr.bin/xlint/xlint/xlint.c
diff -u src/usr.bin/xlint/xlint/xlint.c:1.125 src/usr.bin/xlint/xlint/xlint.c:1.126
--- src/usr.bin/xlint/xlint/xlint.c:1.125	Sun May 12 18:49:36 2024
+++ src/usr.bin/xlint/xlint/xlint.c	Sun Dec  8 17:12:01 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: xlint.c,v 1.125 2024/05/12 18:49:36 rillig Exp $ */
+/* $NetBSD: xlint.c,v 1.126 2024/12/08 17:12:01 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: xlint.c,v 1.125 2024/05/12 18:49:36 rillig Exp $");
+__RCSID("$NetBSD: xlint.c,v 1.126 2024/12/08 17:12:01 rillig Exp $");
 #endif
 
 #include <sys/param.h>
@@ -579,6 +579,7 @@ main(int argc, char *argv[])
 	list_add(&cpp.flags, "-Dlint");	/* XXX don't define with -s */
 	list_add(&cpp.flags, "-D__lint");
 	list_add(&cpp.flags, "-D__lint__");
+	list_add(&cpp.flags, "-dD");
 
 	list_add(&default_libraries, "c");
 

Added files:

Index: src/tests/usr.bin/xlint/lint1/msg_385.c
diff -u /dev/null src/tests/usr.bin/xlint/lint1/msg_385.c:1.1
--- /dev/null	Sun Dec  8 17:12:01 2024
+++ src/tests/usr.bin/xlint/lint1/msg_385.c	Sun Dec  8 17:12:01 2024
@@ -0,0 +1,54 @@
+/*	$NetBSD: msg_385.c,v 1.1 2024/12/08 17:12:01 rillig Exp $	*/
+# 3 "msg_385.c"
+
+// Test for message: do-while macro '%.*s' ends with semicolon [385]
+
+/*
+ * A function-like macro that consists of a do-while statement is intended to
+ * expand to a single statement, but without the trailing semicolon, as the
+ * semicolon is already provided by the calling site. When the macro expansion
+ * ends with a semicolon, there are two semicolons, which can lead to syntax
+ * errors.
+ */
+
+/* lint1-extra-flags: -X 351 */
+
+/* expect+1: warning: do-while macro 'wrong_stmt' ends with semicolon [385] */
+#define		wrong_stmt()	do { } while (0);
+
+#define		correct_stmt()	do { } while (0)
+
+/* expect+5: warning: do-while macro 'wrong_stmt_with_comment' ends with semicolon [385] */
+#define wrong_stmt_with_comment() do { } while (0); /*
+a
+b
+c
+*/
+
+#define correct_stmt_with_comment() do { } while (0) /*
+a
+b
+c
+*/
+
+/* The comment marker inside the string literal does not start a comment. */
+#define stmt_with_string() do { print("/*"); } while (0)
+
+void
+call_wrong_stmt(int x)
+{
+	if (x > 0)
+		do { } while (0);;
+	/* expect+1: error: syntax error 'else' [249] */
+	else
+		do { } while (0);;
+}
+
+void
+call_correct_stmt(int x)
+{
+	if (x < 0)
+		do { } while (0);
+	else
+		do { } while (0);
+}

Reply via email to