Module Name:    src
Committed By:   rillig
Date:           Thu Mar 25 01:42:53 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint/lint1: d_struct_init_nested.c
            d_struct_init_nested.exp
        src/usr.bin/xlint/lint1: init.c

Log Message:
lint: fix C99 initialization with expression of type 'struct'

This has been a long-standing limitation of lint.  Now it is almost
ready for C99, see the list of "major changes" in the foreword of C99.

One known remaining bug in the area of initialization is designators
with several levels, such as '.member[2].member.member'.  Oh, and
designators for arrays are only supported in the parser but not in the
type checker.  There's still some work to do.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/tests/usr.bin/xlint/lint1/d_struct_init_nested.c
cvs rdiff -u -r1.7 -r1.8 \
    src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp
cvs rdiff -u -r1.117 -r1.118 src/usr.bin/xlint/lint1/init.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_struct_init_nested.c
diff -u src/tests/usr.bin/xlint/lint1/d_struct_init_nested.c:1.5 src/tests/usr.bin/xlint/lint1/d_struct_init_nested.c:1.6
--- src/tests/usr.bin/xlint/lint1/d_struct_init_nested.c:1.5	Thu Mar 18 20:58:02 2021
+++ src/tests/usr.bin/xlint/lint1/d_struct_init_nested.c	Thu Mar 25 01:42:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_struct_init_nested.c,v 1.5 2021/03/18 20:58:02 rillig Exp $	*/
+/*	$NetBSD: d_struct_init_nested.c,v 1.6 2021/03/25 01:42:53 rillig Exp $	*/
 # 3 "d_struct_init_nested.c"
 
 /*
@@ -32,9 +32,9 @@ funcOuter3Inner1(void)
 	};
 	struct Outer3Inner1 o3i1 = {
 	    O1C,
-	    inner,		/*FIXME*//* expect: 185 */
+	    inner,
 	    O3C
-	};			/*FIXME*//* expect: 172 */
+	};
 
 	return o3i1.o1;
 }
@@ -59,8 +59,22 @@ funcOuter3Inner2(void)
 	};
 	struct Outer3Inner2 o3i2 = {
 	    O1C,
-	    inner,		/*FIXME*//* expect: 185 */
+	    inner,
 	    O3C
-	};			/*FIXME*//* expect: 210 */
+	};
 	return o3i2.o1;
 }
+
+/*
+ * For static storage duration, each initializer expression must be a constant
+ * expression.
+ */
+struct Inner2 inner = {
+    I1C,
+    I2C
+};
+struct Outer3Inner2 o3i2 = {
+    O1C,
+    inner,			/* expect: non-constant initializer */
+    O3C
+};

Index: src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp
diff -u src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp:1.7 src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp:1.8
--- src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp:1.7	Sun Mar 21 20:44:59 2021
+++ src/tests/usr.bin/xlint/lint1/d_struct_init_nested.exp	Thu Mar 25 01:42:53 2021
@@ -1,4 +1 @@
-d_struct_init_nested.c(35): error: cannot initialize 'enum I1' from 'struct Inner1' [185]
-d_struct_init_nested.c(37): error: too many struct/union initializers [172]
-d_struct_init_nested.c(62): error: cannot initialize 'enum I1' from 'struct Inner2' [185]
-d_struct_init_nested.c(64): warning: enum type mismatch between 'enum I2' and 'enum O3' in initialization [210]
+d_struct_init_nested.c(78): error: non-constant initializer [177]

Index: src/usr.bin/xlint/lint1/init.c
diff -u src/usr.bin/xlint/lint1/init.c:1.117 src/usr.bin/xlint/lint1/init.c:1.118
--- src/usr.bin/xlint/lint1/init.c:1.117	Thu Mar 25 00:48:58 2021
+++ src/usr.bin/xlint/lint1/init.c	Thu Mar 25 01:42:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: init.c,v 1.117 2021/03/25 00:48:58 rillig Exp $	*/
+/*	$NetBSD: init.c,v 1.118 2021/03/25 01:42:53 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: init.c,v 1.117 2021/03/25 00:48:58 rillig Exp $");
+__RCSID("$NetBSD: init.c,v 1.118 2021/03/25 01:42:53 rillig Exp $");
 #endif
 
 #include <stdlib.h>
@@ -382,7 +382,7 @@ begin_initialization(sym_t *sym)
 {
 	struct initialization *curr_init;
 
-	debug_step("begin initialization");
+	debug_step("begin initialization of '%s'", type_name(sym->s_type));
 	curr_init = xcalloc(1, sizeof *curr_init);
 	curr_init->next = init;
 	init = curr_init;
@@ -858,7 +858,7 @@ initstack_next_brace(void)
 }
 
 static void
-initstack_next_nobrace(void)
+initstack_next_nobrace(tnode_t *tn)
 {
 	debug_enter();
 
@@ -871,17 +871,19 @@ initstack_next_nobrace(void)
 	if (!initerr)
 		check_too_many_initializers();
 
-	/*
-	 * Make sure an entry with a scalar type is at the top of the stack.
-	 *
-	 * FIXME: Since C99, an initializer for an object with automatic
-	 *  storage need not be a constant expression anymore.  It is
-	 *  perfectly fine to initialize a struct with a struct expression,
-	 *  see d_struct_init_nested.c for a demonstration.
-	 */
 	while (!initerr) {
-		if ((initstk->i_type != NULL &&
-		     is_scalar(initstk->i_type->t_tspec)))
+		initstack_element *istk = initstk;
+
+		if (tn->tn_type->t_tspec == STRUCT &&
+		    istk->i_type == tn->tn_type &&
+		    istk->i_enclosing != NULL &&
+		    istk->i_enclosing->i_enclosing != NULL) {
+			istk->i_brace = false;
+			istk->i_remaining = 1; /* the struct itself */
+			break;
+		}
+
+		if ((istk->i_type != NULL && is_scalar(istk->i_type->t_tspec)))
 			break;
 		initstack_push();
 	}
@@ -1010,8 +1012,6 @@ check_init_expr(tnode_t *tn, scl_t sclas
 	lt = ln->tn_type->t_tspec;
 	rt = tn->tn_type->t_tspec;
 
-	lint_assert(is_scalar(lt));	/* at least before C99 */
-
 	debug_step("typeok '%s', '%s'",
 	    type_name(ln->tn_type), type_name(tn->tn_type));
 	if (!typeok(INIT, 0, ln, tn))
@@ -1062,7 +1062,7 @@ init_using_expr(tnode_t *tn)
 		goto done_initstack;
 	}
 
-	initstack_next_nobrace();
+	initstack_next_nobrace(tn);
 	if (initerr || tn == NULL)
 		goto done_initstack;
 

Reply via email to