Module Name:    src
Committed By:   rillig
Date:           Wed Dec 22 00:45:53 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint/lint1: d_c99_init.c d_c99_init.exp
            d_init_array_using_string.c d_init_array_using_string.exp init.c
            init.exp msg_179.c msg_179.exp
        src/usr.bin/xlint/lint1: err.c init.c

Log Message:
lint: fix handling of initializations

The implementation from March 2021 added proper support for designators
but didn't model the brace levels correctly.  In particular, it could
not handle additional braces or omitted braces.  In such a case, lint
skipped the remaining initializers from the initialization.  Due to
this, type errors in the remaining initializers went unnoticed.  Another
effect was that arrays of unknown size were wrongly reported as having
size 0.

Both GCC and Clang recommend placing braces around each sub-type that is
initialized, such as a struct, union or array.  Postfix does not follow
these recommendations, therefore lint had to be disabled in
external/ibm-public/postfix/Makefile.inc.  This commit fixes the bugs
mentioned there.


To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/tests/usr.bin/xlint/lint1/d_c99_init.c
cvs rdiff -u -r1.27 -r1.28 src/tests/usr.bin/xlint/lint1/d_c99_init.exp
cvs rdiff -u -r1.7 -r1.8 \
    src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c \
    src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp
cvs rdiff -u -r1.9 -r1.10 src/tests/usr.bin/xlint/lint1/init.c \
    src/tests/usr.bin/xlint/lint1/init.exp
cvs rdiff -u -r1.3 -r1.4 src/tests/usr.bin/xlint/lint1/msg_179.c \
    src/tests/usr.bin/xlint/lint1/msg_179.exp
cvs rdiff -u -r1.149 -r1.150 src/usr.bin/xlint/lint1/err.c
cvs rdiff -u -r1.228 -r1.229 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_c99_init.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_init.c:1.35 src/tests/usr.bin/xlint/lint1/d_c99_init.c:1.36
--- src/tests/usr.bin/xlint/lint1/d_c99_init.c:1.35	Tue Dec 21 16:50:11 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_init.c	Wed Dec 22 00:45:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_c99_init.c,v 1.35 2021/12/21 16:50:11 rillig Exp $	*/
+/*	$NetBSD: d_c99_init.c,v 1.36 2021/12/22 00:45:53 rillig Exp $	*/
 # 3 "d_c99_init.c"
 
 /*
@@ -24,7 +24,7 @@ int scalar_with_too_many_braces = {{ 3 }
 int scalar_with_too_many_initializers = { 3, 5 };	/* expect: 174 */
 
 
-// See init_expr, 'handing over to ASSIGN'.
+// See initialization_expr, 'handing over to INIT'.
 void
 struct_initialization_via_assignment(any arg)
 {
@@ -427,31 +427,46 @@ union value unknown_union_member_name_se
 	.unknown_value = 4,	/* expect: does not have member */
 };
 
-struct point designators_with_subscript = {
+struct point subscript_designator_on_struct = {
 	[0] = 3,		/* expect: only for arrays */
-	.member[0][0].member = 4, /* expect: does not have member 'member' */
-	.x.y.z = 5,	/* intentionally not caught, see designator_look_up */
+};
+
+struct point unknown_member_on_struct = {
+	/* expect+1: error: type 'struct point' does not have member 'member' [101] */
+	.member[0][0].member = 4,
+};
+
+struct point unknown_member_on_scalar = {
+	/* expect+1: error: syntax error 'scalar type cannot use designator' [249] */
+	.x.y.z = 5,
 };
 
 struct {
 	int : 16;
-} struct_with_only_unnamed_members = {	/* expect: has no named members */
-	123,		/* expect: too many struct/union initializers */
+	/* expect+2: warning: structure has no named members [65] */
+	/* expect+1: error: cannot initialize struct/union with no named member [179] */
+} struct_with_only_unnamed_members = {
+	123,
 };
 
 union {
 	int : 16;
-} union_with_only_unnamed_members = {	/* expect: has no named members */
-	123,		/* expect: too many struct/union initializers */
+	/* expect+2: warning: union has no named members [65] */
+	/* expect+1: error: cannot initialize struct/union with no named member [179] */
+} union_with_only_unnamed_members = {
+	123,
 };
 
 int designator_for_scalar = {
 	.value = 3,		/* expect: scalar type cannot use designator */
 };
 
-struct point designator_for_scalar_in_struct = {
+struct point member_designator_for_scalar_in_struct = {
 	{ .x = 3 },		/* expect: scalar type cannot use designator */
-	{ [1] = 4 },		/* expect: scalar type cannot use designator */
+};
+struct point subscript_designator_for_scalar_in_struct = {
+	/* expect+1: error: syntax error 'designator '[...]' is only for arrays' [249] */
+	{ [1] = 4 },
 };
 
 

Index: src/tests/usr.bin/xlint/lint1/d_c99_init.exp
diff -u src/tests/usr.bin/xlint/lint1/d_c99_init.exp:1.27 src/tests/usr.bin/xlint/lint1/d_c99_init.exp:1.28
--- src/tests/usr.bin/xlint/lint1/d_c99_init.exp:1.27	Fri Dec 17 15:52:30 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_init.exp	Wed Dec 22 00:45:53 2021
@@ -18,11 +18,12 @@ d_c99_init.c(412): error: type 'struct p
 d_c99_init.c(421): error: type 'union value' does not have member 'unknown_value' [101]
 d_c99_init.c(427): error: type 'union value' does not have member 'unknown_value' [101]
 d_c99_init.c(431): error: syntax error 'designator '[...]' is only for arrays' [249]
-d_c99_init.c(432): error: type 'struct point' does not have member 'member' [101]
-d_c99_init.c(438): warning: structure has no named members [65]
-d_c99_init.c(439): error: too many struct/union initializers [172]
-d_c99_init.c(444): warning: union has no named members [65]
-d_c99_init.c(445): error: too many struct/union initializers [172]
-d_c99_init.c(449): error: syntax error 'scalar type cannot use designator' [249]
-d_c99_init.c(453): error: syntax error 'scalar type cannot use designator' [249]
-d_c99_init.c(454): error: syntax error 'scalar type cannot use designator' [249]
+d_c99_init.c(436): error: type 'struct point' does not have member 'member' [101]
+d_c99_init.c(441): error: syntax error 'scalar type cannot use designator' [249]
+d_c99_init.c(448): warning: structure has no named members [65]
+d_c99_init.c(448): error: cannot initialize struct/union with no named member [179]
+d_c99_init.c(456): warning: union has no named members [65]
+d_c99_init.c(456): error: cannot initialize struct/union with no named member [179]
+d_c99_init.c(461): error: syntax error 'scalar type cannot use designator' [249]
+d_c99_init.c(465): error: syntax error 'scalar type cannot use designator' [249]
+d_c99_init.c(469): error: syntax error 'designator '[...]' is only for arrays' [249]

Index: src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c
diff -u src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c:1.7 src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c:1.8
--- src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c:1.7	Tue Dec 21 22:21:11 2021
+++ src/tests/usr.bin/xlint/lint1/d_init_array_using_string.c	Wed Dec 22 00:45:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: d_init_array_using_string.c,v 1.7 2021/12/21 22:21:11 rillig Exp $	*/
+/*	$NetBSD: d_init_array_using_string.c,v 1.8 2021/12/22 00:45:53 rillig Exp $	*/
 # 3 "d_init_array_using_string.c"
 
 /*
@@ -60,8 +60,8 @@ test_array_initialization_in_struct(void
 	};
 
 	struct cs_ws type_mismatch = {
-		L"",		/* expect: cannot initialize */
-		"",		/* expect: cannot initialize */
+		L"",		/* expect: warning: illegal combination of integer (char) and pointer (pointer to int) [183] */
+		"",		/* expect: warning: illegal combination of integer (char) and pointer (pointer to char) [183] */
 	};
 
 	struct cs_ws no_terminating_null = {
Index: src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp
diff -u src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp:1.7 src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp:1.8
--- src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp:1.7	Tue Dec 21 22:21:11 2021
+++ src/tests/usr.bin/xlint/lint1/d_init_array_using_string.exp	Wed Dec 22 00:45:53 2021
@@ -2,7 +2,7 @@ d_init_array_using_string.c(17): warning
 d_init_array_using_string.c(19): warning: illegal combination of 'pointer to const int' and 'pointer to char', op 'init' [124]
 d_init_array_using_string.c(37): warning: illegal combination of 'pointer to const char' and 'pointer to int', op 'init' [124]
 d_init_array_using_string.c(39): warning: illegal combination of 'pointer to const int' and 'pointer to char', op 'init' [124]
-d_init_array_using_string.c(63): error: cannot initialize 'array[10] of const char' from 'pointer to int' [185]
-d_init_array_using_string.c(64): error: cannot initialize 'array[10] of const int' from 'pointer to char' [185]
+d_init_array_using_string.c(63): warning: illegal combination of integer (char) and pointer (pointer to int) [183]
+d_init_array_using_string.c(64): warning: illegal combination of integer (char) and pointer (pointer to char) [183]
 d_init_array_using_string.c(74): warning: string literal too long (11) for target array (10) [187]
 d_init_array_using_string.c(76): warning: string literal too long (11) for target array (10) [187]

Index: src/tests/usr.bin/xlint/lint1/init.c
diff -u src/tests/usr.bin/xlint/lint1/init.c:1.9 src/tests/usr.bin/xlint/lint1/init.c:1.10
--- src/tests/usr.bin/xlint/lint1/init.c:1.9	Tue Dec 21 21:42:21 2021
+++ src/tests/usr.bin/xlint/lint1/init.c	Wed Dec 22 00:45:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: init.c,v 1.9 2021/12/21 21:42:21 rillig Exp $	*/
+/*	$NetBSD: init.c,v 1.10 2021/12/22 00:45:53 rillig Exp $	*/
 # 3 "init.c"
 
 /*
@@ -106,3 +106,27 @@ union incomplete_union u2 = {
 union incomplete_union {
 	int num;
 };
+
+
+/* expect+1: warning: cannot initialize extern declaration: extern_var [26] */
+extern int extern_var = 1;
+int defined_var = 1;
+/* expect+1: warning: static variable static_var unused [226] */
+static int static_var = 1;
+/* expect+1: error: illegal storage class [8] */
+register int register_var = 1;
+/* expect+1: error: cannot initialize typedef: typedef_var [25] */
+typedef int typedef_var = 1;
+
+
+/*
+ * In an array of unknown size that is declared using fewer braces than
+ * recommended, ensure that the array size is updated at the end of the
+ * initializer.
+ */
+struct {
+	int x;
+	int y;
+} points_of_unknown_size[] = {
+	3, 4,
+};
Index: src/tests/usr.bin/xlint/lint1/init.exp
diff -u src/tests/usr.bin/xlint/lint1/init.exp:1.9 src/tests/usr.bin/xlint/lint1/init.exp:1.10
--- src/tests/usr.bin/xlint/lint1/init.exp:1.9	Tue Dec 21 21:42:21 2021
+++ src/tests/usr.bin/xlint/lint1/init.exp	Wed Dec 22 00:45:53 2021
@@ -7,3 +7,7 @@ init.c(95): error: initialization of inc
 init.c(98): error: 'u1' has incomplete type 'incomplete union incomplete_union' [31]
 init.c(101): error: initialization of incomplete type 'incomplete union incomplete_union' [175]
 init.c(104): error: 'u2' has incomplete type 'incomplete union incomplete_union' [31]
+init.c(112): warning: cannot initialize extern declaration: extern_var [26]
+init.c(117): error: illegal storage class [8]
+init.c(119): error: cannot initialize typedef: typedef_var [25]
+init.c(115): warning: static variable static_var unused [226]

Index: src/tests/usr.bin/xlint/lint1/msg_179.c
diff -u src/tests/usr.bin/xlint/lint1/msg_179.c:1.3 src/tests/usr.bin/xlint/lint1/msg_179.c:1.4
--- src/tests/usr.bin/xlint/lint1/msg_179.c:1.3	Fri Aug 27 19:50:44 2021
+++ src/tests/usr.bin/xlint/lint1/msg_179.c	Wed Dec 22 00:45:53 2021
@@ -1,24 +1,25 @@
-/*	$NetBSD: msg_179.c,v 1.3 2021/08/27 19:50:44 rillig Exp $	*/
+/*	$NetBSD: msg_179.c,v 1.4 2021/12/22 00:45:53 rillig Exp $	*/
 # 3 "msg_179.c"
 
 // Test for message: cannot initialize struct/union with no named member [179]
-/* This message is not used. */
 
 struct {
 	unsigned int :0;
 } no_named_member = {
+	/* expect-1: error: cannot initialize struct/union with no named member [179] */
 	/* no named member, therefore no initializer expression */
 };
 
 struct {
 	/* no members */
 } empty = {
+	/* expect-1: error: cannot initialize struct/union with no named member [179] */
 	/* no initializer expressions */
 };
 
 struct {
 	unsigned int: 0;
 } no_named_member_init = {
-	/* expect+1: error: too many struct/union initializers [172] */
+	/* expect-1: error: cannot initialize struct/union with no named member [179] */
 	3,
 };
Index: src/tests/usr.bin/xlint/lint1/msg_179.exp
diff -u src/tests/usr.bin/xlint/lint1/msg_179.exp:1.3 src/tests/usr.bin/xlint/lint1/msg_179.exp:1.4
--- src/tests/usr.bin/xlint/lint1/msg_179.exp:1.3	Fri Aug 27 19:50:44 2021
+++ src/tests/usr.bin/xlint/lint1/msg_179.exp	Wed Dec 22 00:45:53 2021
@@ -1 +1,3 @@
-msg_179.c(23): error: too many struct/union initializers [172]
+msg_179.c(8): error: cannot initialize struct/union with no named member [179]
+msg_179.c(15): error: cannot initialize struct/union with no named member [179]
+msg_179.c(22): error: cannot initialize struct/union with no named member [179]

Index: src/usr.bin/xlint/lint1/err.c
diff -u src/usr.bin/xlint/lint1/err.c:1.149 src/usr.bin/xlint/lint1/err.c:1.150
--- src/usr.bin/xlint/lint1/err.c:1.149	Tue Dec 21 22:21:11 2021
+++ src/usr.bin/xlint/lint1/err.c	Wed Dec 22 00:45:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: err.c,v 1.149 2021/12/21 22:21:11 rillig Exp $	*/
+/*	$NetBSD: err.c,v 1.150 2021/12/22 00:45:53 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: err.c,v 1.149 2021/12/21 22:21:11 rillig Exp $");
+__RCSID("$NetBSD: err.c,v 1.150 2021/12/22 00:45:53 rillig Exp $");
 #endif
 
 #include <sys/types.h>
@@ -233,7 +233,7 @@ const char *const msgs[] = {
 	"",			/* no longer used */		      /* 176 */
 	"non-constant initializer",				      /* 177 */
 	"initializer does not fit",				      /* 178 */
-	"",			/* unused since 2021-03-29 */	      /* 179 */
+	"cannot initialize struct/union with no named member",	      /* 179 */
 	"bit-field initializer does not fit",			      /* 180 */
 	"{}-enclosed initializer required",			      /* 181 */
 	"incompatible pointer types (%s != %s)",		      /* 182 */

Index: src/usr.bin/xlint/lint1/init.c
diff -u src/usr.bin/xlint/lint1/init.c:1.228 src/usr.bin/xlint/lint1/init.c:1.229
--- src/usr.bin/xlint/lint1/init.c:1.228	Tue Dec 21 22:21:11 2021
+++ src/usr.bin/xlint/lint1/init.c	Wed Dec 22 00:45:53 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: init.c,v 1.228 2021/12/21 22:21:11 rillig Exp $	*/
+/*	$NetBSD: init.c,v 1.229 2021/12/22 00:45:53 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: init.c,v 1.228 2021/12/21 22:21:11 rillig Exp $");
+__RCSID("$NetBSD: init.c,v 1.229 2021/12/22 00:45:53 rillig Exp $");
 #endif
 
 #include <stdlib.h>
@@ -52,21 +52,9 @@ __RCSID("$NetBSD: init.c,v 1.228 2021/12
  *
  *	int number = 12345;
  *	int number_with_braces = { 12345 };
- *
  *	int array_of_unknown_size[] = { 111, 222, 333 };
- *	int array_flat[2][2] = { 11, 12, 21, 22 };
- *	int array_nested[2][2] = { { 11, 12 }, { 21, 22 } };
- *
- *	struct { int x, y; } point = { 3, 4 };
  *	struct { int x, y; } point = { .y = 4, .x = 3 };
  *
- * Any scalar expression or string in the initializer may be surrounded by
- * additional pairs of braces.
- *
- * For nested aggregate objects, the inner braces may be omitted like in
- * array_flat or spelled out like in array_nested.  This is unusual in
- * practice and therefore only supported very basically.
- *
  * During an initialization, the grammar parser calls these functions:
  *
  *	begin_initialization
@@ -87,22 +75,33 @@ __RCSID("$NetBSD: init.c,v 1.228 2021/12
  *	d_c99_init.c for more examples
  */
 
+
+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 to the sub-object that is initialized by an
- * initializer expression.  Either a struct or union member, or an array
- * subscript.
+ * 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 {
-	const char	*dr_name;	/* for struct and union */
-	size_t		dr_subscript;	/* for array */
+	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
- * will be initialized by the next expression.  Examples for designations are
- * '.member' or '.member[123].member.member[1][1]'.
+ * is initialized by an expression.  Examples for designations are '.member'
+ * or '.member[123].member.member[1][1]'.
  *
  * C99 6.7.8p6, 6.7.8p7
  */
@@ -113,8 +112,13 @@ typedef struct designation {
 } designation;
 
 /*
- * Everything that happens between a '{' and the corresponding '}' of an
- * initialization.
+ * Everything that happens between a '{' and the corresponding '}', as part
+ * of an initialization.
+ *
+ * Each brace level has a "current object".   For the outermost brace level,
+ * it is the same as the object to be initialized.  Each nested '{' begins a
+ * nested brace level, for the sub-object pointed to by the designator of the
+ * outer brace level.
  *
  * C99 6.7.8p17
  */
@@ -123,52 +127,25 @@ typedef struct brace_level {
 	const type_t	*bl_type;
 
 	/*
-	 * The path to the sub-object of the "current object" that is
+	 * The path from the "current object" to the sub-object that is
 	 * initialized by the next expression.
 	 *
-	 * TODO: use this not only for explicit designations but also for
-	 *  implicit designations, like in C90.
+	 * Initially, the designation is empty.  Before handling an
+	 * expression, the designation is updated to point to the
+	 * corresponding sub-object to be initialized.  After handling an
+	 * expression, the designation is marked as done.  It is later
+	 * advanced as necessary.
 	 */
 	designation	bl_designation;
 
-	/*
-	 * The next member of the struct or union that is to be initialized,
-	 * unless a specific member is selected by a designator.
-	 *
-	 * TODO: use bl_designation instead.
-	 */
-	const sym_t	*bl_member;
-	/*
-	 * The subscript of the next array element that is to be initialized,
-	 * unless a specific subscript is selected by a designator.
-	 *
-	 * TODO: use bl_designation instead.
-	 */
-	size_t		bl_subscript;
-
-	/*
-	 * Whether the designation is used up, that is, there is no next
-	 * sub-object left to be initialized.
-	 */
-	bool		bl_scalar_done:1;	/* for scalars */
-
-	/*
-	 * Whether lint has been confused by allowed but extra or omitted
-	 * braces.  In such a case, lint skips further type checks on the
-	 * initializer expressions.
-	 *
-	 * TODO: properly handle the omitted braces.
-	 */
-	bool		bl_confused:1;
-
 	struct brace_level *bl_enclosing;
 } brace_level;
 
 /*
  * An ongoing initialization.
  *
- * In most cases there is only ever a single initialization going on.  See
- * pointer_to_compound_literal in msg_171.c for an exception.
+ * In most cases there is only ever a single initialization at a time.  See
+ * pointer_to_compound_literal in msg_171.c for a real-life counterexample.
  */
 typedef struct initialization {
 	/* The symbol that is to be initialized. */
@@ -178,16 +155,15 @@ typedef struct initialization {
 	brace_level	*in_brace_level;
 
 	/*
-	 * The maximum subscript that has ever be seen for an array of
+	 * The maximum subscript that has ever been seen for an array of
 	 * unknown size, which can only occur at the outermost brace level.
 	 */
 	size_t		in_max_subscript;
 
 	/*
 	 * Is set when a structural error occurred in the initialization.
-	 * The effect is that the rest of the initialization is ignored
-	 * (parsed by yacc, expression trees built, but no initialization
-	 * takes place).
+	 * If set, the rest of the initialization is still parsed, but the
+	 * initialization assignments are not checked.
 	 */
 	bool		in_err;
 
@@ -211,27 +187,27 @@ has_automatic_storage_duration(const sym
 	return sym->s_scl == AUTO || sym->s_scl == REG;
 }
 
-/* C99 6.7.8p14, 6.7.8p15 */
+/*
+ * Test whether rn is a string literal that can initialize ltp.
+ *
+ * See also:
+ *	C99 6.7.8p14		for plain character strings
+ *	C99 6.7.8p15		for wide character strings
+ */
 static bool
-is_character_array(const type_t *tp, tspec_t t)
+can_init_character_array(const type_t *ltp, const tnode_t *rn)
 {
-	tspec_t st;
+	tspec_t lst, rst;
 
-	if (tp == NULL || tp->t_tspec != ARRAY)
+	if (!(ltp != NULL && ltp->t_tspec == ARRAY && rn->tn_op == STRING))
 		return false;
 
-	st = tp->t_subt->t_tspec;
-	return t == CHAR
-	    ? st == CHAR || st == UCHAR || st == SCHAR
-	    : st == WCHAR;
-}
-
-/* C99 6.7.8p9 */
-static bool
-is_unnamed(const sym_t *m)
-{
+	lst = ltp->t_subt->t_tspec;
+	rst = rn->tn_type->t_subt->t_tspec;
 
-	return m->s_bitfield && m->s_name == unnamed;
+	return rst == CHAR
+	    ? lst == CHAR || lst == UCHAR || lst == SCHAR
+	    : lst == WCHAR;
 }
 
 /* C99 6.7.8p9 */
@@ -239,7 +215,7 @@ static const sym_t *
 skip_unnamed(const sym_t *m)
 {
 
-	while (m != NULL && is_unnamed(m))
+	while (m != NULL && m->s_name == unnamed)
 		m = m->s_next;
 	return m;
 }
@@ -259,32 +235,11 @@ look_up_member(const type_t *tp, const c
 
 	lint_assert(is_struct_or_union(tp->t_tspec));
 	for (m = tp->t_str->sou_first_member; m != NULL; m = m->s_next)
-		if (!is_unnamed(m) && strcmp(m->s_name, name) == 0)
+		if (strcmp(m->s_name, name) == 0)
 			return m;
 	return NULL;
 }
 
-static const type_t *
-sym_type(const sym_t *sym)
-{
-
-	return sym != NULL ? sym->s_type : NULL;
-}
-
-static const type_t *
-look_up_member_type(const type_t *tp, const char *name)
-{
-	const sym_t *member;
-
-	member = look_up_member(tp, name);
-	if (member == NULL) {
-		/* type '%s' does not have member '%s' */
-		error(101, type_name(tp), name);
-	}
-
-	return sym_type(member);
-}
-
 /*
  * C99 6.7.8p22 says that the type of an array of unknown size becomes known
  * at the end of its initializer list.
@@ -298,6 +253,7 @@ update_type_of_array_of_unknown_size(sym
 	tp->t_dim = (int)size;
 	tp->t_incomplete_array = false;
 	sym->s_type = tp;
+	debug_step("completed array type is '%s'", type_name(sym->s_type));
 }
 
 
@@ -400,28 +356,29 @@ designator_type(const designator *dr, co
 	switch (tp->t_tspec) {
 	case STRUCT:
 	case UNION:
-		if (dr->dr_name == NULL) {
+		if (dr->dr_kind != DK_STRUCT && dr->dr_kind != DK_UNION) {
+			const sym_t *fmem = first_named_member(tp);
 			/* syntax error '%s' */
 			error(249, "designator '[...]' is only for arrays");
-			return sym_type(first_named_member(tp));
+			return fmem != NULL ? fmem->s_type : NULL;
 		}
 
-		return look_up_member_type(tp, dr->dr_name);
+		lint_assert(dr->dr_member != NULL);
+		return dr->dr_member->s_type;
 	case ARRAY:
-		if (dr->dr_name != NULL) {
+		if (dr->dr_kind != DK_ARRAY) {
 			/* syntax error '%s' */
 			error(249,
 			    "designator '.member' is only for struct/union");
 		}
-		if (!tp->t_incomplete_array &&
-		    dr->dr_subscript >= (size_t)tp->t_dim) {
-			/* array subscript cannot be > %d: %ld */
-			error(168, tp->t_dim - 1, (long)dr->dr_subscript);
-		}
+		if (!tp->t_incomplete_array)
+			lint_assert(dr->dr_subscript < (size_t)tp->t_dim);
 		return tp->t_subt;
 	default:
-		/* syntax error '%s' */
-		error(249, "scalar type cannot use designator");
+		if (dr->dr_kind != DK_SCALAR) {
+			/* syntax error '%s' */
+			error(249, "scalar type cannot use designator");
+		}
 		return tp;
 	}
 }
@@ -429,32 +386,61 @@ designator_type(const designator *dr, co
 
 #ifdef DEBUG
 static void
+designator_debug(const designator *dr)
+{
+
+	if (dr->dr_kind == DK_STRUCT || dr->dr_kind == DK_UNION) {
+		lint_assert(dr->dr_subscript == 0);
+		debug_printf(".%s",
+		    dr->dr_member != NULL
+			? dr->dr_member->s_name
+			: "<end>");
+	} else if (dr->dr_kind == DK_ARRAY) {
+		lint_assert(dr->dr_member == NULL);
+		debug_printf("[%zu]", dr->dr_subscript);
+	} else {
+		lint_assert(dr->dr_member == NULL);
+		lint_assert(dr->dr_subscript == 0);
+		debug_printf("<scalar>");
+	}
+
+	if (dr->dr_done)
+		debug_printf(" (done)");
+}
+
+static void
 designation_debug(const designation *dn)
 {
 	size_t i;
 
-	if (dn->dn_len == 0)
+	if (dn->dn_len == 0) {
+		debug_step("designation: (empty)");
 		return;
+	}
 
 	debug_print_indent();
 	debug_printf("designation: ");
-	for (i = 0; i < dn->dn_len; i++) {
-		const designator *dr = dn->dn_items + i;
-		if (dr->dr_name != NULL) {
-			debug_printf(".%s", dr->dr_name);
-			lint_assert(dr->dr_subscript == 0);
-		} else
-			debug_printf("[%zu]", dr->dr_subscript);
-	}
+	for (i = 0; i < dn->dn_len; i++)
+		designator_debug(dn->dn_items + i);
 	debug_printf("\n");
 }
 #else
 #define designation_debug(dn) do { } while (false)
 #endif
 
+static designator *
+designation_last(designation *dn)
+{
+
+	lint_assert(dn->dn_len > 0);
+	return &dn->dn_items[dn->dn_len - 1];
+}
+
 static void
-designation_add(designation *dn, const char *name, size_t subscript)
+designation_push(designation *dn, designator_kind kind,
+		 const sym_t *member, size_t subscript)
 {
+	designator *dr;
 
 	if (dn->dn_len == dn->dn_cap) {
 		dn->dn_cap += 4;
@@ -462,9 +448,34 @@ designation_add(designation *dn, const c
 		    dn->dn_cap * sizeof(dn->dn_items[0]));
 	}
 
-	dn->dn_items[dn->dn_len].dr_name = name;
-	dn->dn_items[dn->dn_len].dr_subscript = subscript;
-	dn->dn_len++;
+	dr = &dn->dn_items[dn->dn_len++];
+	dr->dr_kind = kind;
+	dr->dr_member = member;
+	dr->dr_subscript = subscript;
+	dr->dr_done = false;
+	designation_debug(dn);
+}
+
+/*
+ * Extend the designation as appropriate for the given type.
+ *
+ * C11 6.7.9p17
+ */
+static bool
+designation_descend(designation *dn, const type_t *tp)
+{
+
+	if (is_struct_or_union(tp->t_tspec)) {
+		const sym_t *member = first_named_member(tp);
+		if (member == NULL)
+			return false;
+		designation_push(dn,
+		    tp->t_tspec == STRUCT ? DK_STRUCT : DK_UNION, member, 0);
+	} else if (tp->t_tspec == ARRAY)
+		designation_push(dn, DK_ARRAY, NULL, 0);
+	else
+		designation_push(dn, DK_SCALAR, NULL, 0);
+	return true;
 }
 
 /*
@@ -483,18 +494,14 @@ designation_type(const designation *dn, 
 	return tp;
 }
 
-static void
-designation_reset(designation *dn)
-{
-
-	dn->dn_len = 0;
-}
-
-static void
-designation_free(designation *dn)
+static const type_t *
+designation_parent_type(const designation *dn, const type_t *tp)
 {
+	size_t i;
 
-	free(dn->dn_items);
+	for (i = 0; i + 1 < dn->dn_len && tp != NULL; i++)
+		tp = designator_type(dn->dn_items + i, tp);
+	return tp;
 }
 
 
@@ -506,8 +513,6 @@ brace_level_new(const type_t *tp, brace_
 	bl = xcalloc(1, sizeof(*bl));
 	bl->bl_type = tp;
 	bl->bl_enclosing = enclosing;
-	if (is_struct_or_union(tp->t_tspec))
-		bl->bl_member = first_named_member(tp);
 
 	return bl;
 }
@@ -516,7 +521,7 @@ static void
 brace_level_free(brace_level *bl)
 {
 
-	designation_free(&bl->bl_designation);
+	free(bl->bl_designation.dn_items);
 	free(bl);
 }
 
@@ -526,16 +531,11 @@ brace_level_debug(const brace_level *bl)
 {
 
 	lint_assert(bl->bl_type != NULL);
-	lint_assert(bl->bl_member == NULL || !is_unnamed(bl->bl_member));
-
-	debug_printf("type '%s'", type_name(bl->bl_type));
-
-	if (is_struct_or_union(bl->bl_type->t_tspec) && bl->bl_member != NULL)
-		debug_printf(", member '%s'", bl->bl_member->s_name);
-	if (bl->bl_type->t_tspec == ARRAY)
-		debug_printf(", subscript %zu", bl->bl_subscript);
 
-	debug_printf("\n");
+	debug_printf("type '%s'\n", type_name(bl->bl_type));
+	debug_indent_inc();
+	designation_debug(&bl->bl_designation);
+	debug_indent_dec();
 }
 #else
 #define brace_level_debug(level) do { } while (false)
@@ -543,101 +543,149 @@ brace_level_debug(const brace_level *bl)
 
 /* Return the type of the sub-object that is currently being initialized. */
 static const type_t *
-brace_level_sub_type(const brace_level *bl, bool is_string)
+brace_level_sub_type(const brace_level *bl)
 {
 
-	if (bl->bl_designation.dn_len > 0)
-		return designation_type(&bl->bl_designation, bl->bl_type);
+	return designation_type(&bl->bl_designation, bl->bl_type);
+}
 
-	switch (bl->bl_type->t_tspec) {
+/*
+ * After initializing a sub-object, advance the designation to point after
+ * the sub-object that has just been initialized.
+ *
+ * C99 6.7.8p17
+ * C11 6.7.9p17
+ */
+static void
+brace_level_advance(brace_level *bl, size_t *max_subscript)
+{
+	const type_t *tp;
+	designation *dn;
+	designator *dr;
+
+	debug_enter();
+	dn = &bl->bl_designation;
+	tp = designation_parent_type(dn, bl->bl_type);
+
+	if (bl->bl_designation.dn_len == 0)
+		designation_descend(dn, bl->bl_type);
+	dr = designation_last(dn);
+	/* TODO: try to switch on dr->dr_kind instead */
+	switch (tp->t_tspec) {
 	case STRUCT:
+		lint_assert(dr->dr_member != NULL);
+		dr->dr_member = skip_unnamed(dr->dr_member->s_next);
+		if (dr->dr_member == NULL)
+			dr->dr_done = true;
+		break;
 	case UNION:
-		if (bl->bl_member == NULL) {
-			/* too many struct/union initializers */
-			error(172);
-			return NULL;
-		}
+		dr->dr_member = NULL;
+		dr->dr_done = true;
+		break;
+	case ARRAY:
+		dr->dr_subscript++;
+		if (tp->t_incomplete_array &&
+		    dr->dr_subscript > *max_subscript)
+			*max_subscript = dr->dr_subscript;
+		if (!tp->t_incomplete_array &&
+		    dr->dr_subscript >= (size_t)tp->t_dim)
+			dr->dr_done = true;
+		break;
+	default:
+		dr->dr_done = true;
+		break;
+	}
+	designation_debug(dn);
+	debug_leave();
+}
 
-		lint_assert(!is_unnamed(bl->bl_member));
-		return sym_type(bl->bl_member);
+static void
+warn_too_many_initializers(designator_kind kind, const type_t *tp)
+{
 
-	case ARRAY:
-		if (!bl->bl_confused && !bl->bl_type->t_incomplete_array &&
-		    bl->bl_subscript >= (size_t)bl->bl_type->t_dim) {
-			/* too many array initializers, expected %d */
-			error(173, bl->bl_type->t_dim);
-		}
+	if (kind == DK_STRUCT || kind == DK_UNION) {
+		/* too many struct/union initializers */
+		error(172);
+	} else if (kind == DK_ARRAY) {
+		lint_assert(tp->t_tspec == ARRAY);
+		lint_assert(!tp->t_incomplete_array);
+		/* too many array initializers, expected %d */
+		error(173, tp->t_dim);
+	} else {
+		/* too many initializers */
+		error(174);
+	}
 
-		if (is_string && bl->bl_subscript == 0 &&
-		    bl->bl_type->t_subt->t_tspec != ARRAY)
-			return bl->bl_type;
-		return bl->bl_type->t_subt;
+}
 
-	default:
-		if (bl->bl_scalar_done) {
-			/* too many initializers */
-			error(174);
+static bool
+brace_level_pop_done(brace_level *bl, size_t *max_subscript)
+{
+	designation *dn = &bl->bl_designation;
+	designator_kind dr_kind = designation_last(dn)->dr_kind;
+	const type_t *sub_type = designation_parent_type(dn, bl->bl_type);
+
+	while (designation_last(dn)->dr_done) {
+		dn->dn_len--;
+		designation_debug(dn);
+		if (dn->dn_len == 0) {
+			warn_too_many_initializers(dr_kind, sub_type);
+			return false;
 		}
-
-		return bl->bl_type;
+		brace_level_advance(bl, max_subscript);
 	}
+	return true;
 }
 
-/* C99 6.7.8p17 */
 static void
-brace_level_apply_designation(brace_level *bl)
+brace_level_pop_final(brace_level *bl, size_t *max_subscript)
 {
-	const designator *dr;
+	designation *dn = &bl->bl_designation;
 
-	if (bl->bl_designation.dn_len == 0)
-		return;
-	dr = &bl->bl_designation.dn_items[0];
-
-	designation_debug(&bl->bl_designation);
-
-	switch (bl->bl_type->t_tspec) {
-	case STRUCT:
-	case UNION:
-		if (dr->dr_name == NULL)
-			return;	/* error, silently ignored */
-		bl->bl_member = look_up_member(bl->bl_type, dr->dr_name);
-		break;
-	case ARRAY:
-		if (dr->dr_name != NULL)
-			return;	/* error, silently ignored */
-		bl->bl_subscript = dr->dr_subscript;
-		break;
-	default:
-		break;		/* error, silently ignored */
+	while (dn->dn_len > 0 && designation_last(dn)->dr_done) {
+		dn->dn_len--;
+		designation_debug(dn);
+		if (dn->dn_len == 0)
+			return;
+		brace_level_advance(bl, max_subscript);
 	}
 }
 
 /*
- * After initializing a sub-object, advance to the next sub-object.
- *
- * C99 6.7.8p17
+ * Make the designation point to the sub-object to be initialized next.
+ * Initially or after a previous expression, the designation is not advanced
+ * yet since the place to stop depends on the next expression, especially for
+ * string literals.
  */
-static void
-brace_level_advance(brace_level *bl, size_t *max_subscript)
+static bool
+brace_level_goto(brace_level *bl, const tnode_t *rn, size_t *max_subscript)
 {
+	const type_t *ltp;
+	designation *dn;
 
-	switch (bl->bl_type->t_tspec) {
-	case STRUCT:
-		lint_assert(bl->bl_member != NULL);
-		bl->bl_member = skip_unnamed(bl->bl_member->s_next);
-		break;
-	case UNION:
-		bl->bl_member = NULL;
-		break;
-	case ARRAY:
-		bl->bl_subscript++;
-		if (bl->bl_subscript > *max_subscript)
-			*max_subscript = bl->bl_subscript;
-		break;
-	default:
-		bl->bl_scalar_done = true;
-		break;
+	dn = &bl->bl_designation;
+	if (dn->dn_len == 0 && can_init_character_array(bl->bl_type, rn))
+		return true;
+	if (dn->dn_len == 0 && !designation_descend(dn, bl->bl_type))
+		return false;
+
+again:
+	if (!brace_level_pop_done(bl, max_subscript))
+		return false;
+
+	ltp = brace_level_sub_type(bl);
+	if (eqtype(ltp, rn->tn_type, true, false, NULL))
+		return true;
+
+	if (is_struct_or_union(ltp->t_tspec) || ltp->t_tspec == ARRAY) {
+		if (can_init_character_array(ltp, rn))
+			return true;
+		if (!designation_descend(dn, ltp))
+			return false;
+		goto again;
 	}
+
+	return true;
 }
 
 
@@ -658,6 +706,7 @@ initialization_free(initialization *in)
 {
 	brace_level *bl, *next;
 
+	/* TODO: lint_assert(in->in_brace_level == NULL) */
 	for (bl = in->in_brace_level; bl != NULL; bl = next) {
 		next = bl->bl_enclosing;
 		brace_level_free(bl);
@@ -673,6 +722,8 @@ initialization_debug(const initializatio
 	size_t i;
 	const brace_level *bl;
 
+	if (in->in_err)
+		debug_step("initialization error");
 	if (in->in_brace_level == NULL) {
 		debug_step("no brace level");
 		return;
@@ -695,13 +746,14 @@ initialization_debug(const initializatio
  * initialized.
  */
 static const type_t *
-initialization_sub_type(initialization *in, bool is_string)
+initialization_sub_type(initialization *in)
 {
 	const type_t *tp;
 
-	tp = in->in_brace_level != NULL
-	    ? brace_level_sub_type(in->in_brace_level, is_string)
-	    : in->in_sym->s_type;
+	if (in->in_brace_level == NULL)
+		return in->in_sym->s_type;
+
+	tp = brace_level_sub_type(in->in_brace_level);
 	if (tp == NULL)
 		in->in_err = true;
 	return tp;
@@ -711,19 +763,19 @@ static void
 initialization_lbrace(initialization *in)
 {
 	const type_t *tp;
+	brace_level *outer_bl;
 
 	if (in->in_err)
 		return;
 
 	debug_enter();
 
-	tp = initialization_sub_type(in, false);
-	if (tp == NULL) {
-		in->in_err = true;
+	tp = initialization_sub_type(in);
+	if (tp == NULL)
 		goto done;
-	}
 
-	if (tflag && in->in_brace_level == NULL)
+	outer_bl = in->in_brace_level;
+	if (tflag && outer_bl == NULL)
 		check_trad_no_auto_aggregate(in->in_sym);
 
 	if (tflag && tp->t_tspec == UNION) {
@@ -738,33 +790,25 @@ initialization_lbrace(initialization *in
 		goto done;
 	}
 
-	if (in->in_brace_level != NULL)
-		brace_level_apply_designation(in->in_brace_level);
+	if (outer_bl != NULL && outer_bl->bl_designation.dn_len == 0) {
+		designation *dn = &outer_bl->bl_designation;
+		designation_descend(dn, outer_bl->bl_type);
+		tp = designation_type(dn, outer_bl->bl_type);
+	}
 
-	in->in_brace_level = brace_level_new(tp, in->in_brace_level);
+	in->in_brace_level = brace_level_new(tp, outer_bl);
+	if (is_struct_or_union(tp->t_tspec) &&
+	    first_named_member(tp) == NULL) {
+		/* cannot initialize struct/union with no named member */
+		error(179);
+		in->in_err = true;
+	}
 
 done:
 	initialization_debug(in);
 	debug_leave();
 }
 
-/* C99 6.7.8p22 */
-static void
-initialization_set_size_of_unknown_array(initialization *in)
-{
-	size_t dim;
-
-	if (!(in->in_sym->s_type->t_incomplete_array &&
-	      in->in_brace_level->bl_enclosing == NULL))
-		return;
-
-	dim = in->in_max_subscript;
-	if (dim == 0 && (in->in_err || in->in_brace_level->bl_confused))
-		dim = 1;	/* prevent "empty array declaration: %s" */
-
-	update_type_of_array_of_unknown_size(in->in_sym, dim);
-}
-
 static void
 initialization_rbrace(initialization *in)
 {
@@ -772,7 +816,22 @@ initialization_rbrace(initialization *in
 
 	debug_enter();
 
-	initialization_set_size_of_unknown_array(in);
+	if (in->in_brace_level != NULL)
+		brace_level_pop_final(in->in_brace_level,
+		    &in->in_max_subscript);
+
+	/* C99 6.7.8p22 */
+	if (in->in_sym->s_type->t_incomplete_array &&
+	    in->in_brace_level->bl_enclosing == NULL) {
+
+		/* prevent "empty array declaration: %s" */
+		size_t dim = in->in_max_subscript;
+		if (dim == 0 && in->in_err)
+			dim = 1;
+
+		update_type_of_array_of_unknown_size(in->in_sym, dim);
+	}
+
 	if (in->in_err)
 		goto done;
 
@@ -781,10 +840,8 @@ initialization_rbrace(initialization *in
 	in->in_brace_level = outer_bl;
 	brace_level_free(inner_bl);
 
-	if (outer_bl != NULL) {
+	if (outer_bl != NULL)
 		brace_level_advance(outer_bl, &in->in_max_subscript);
-		designation_reset(&outer_bl->bl_designation);
-	}
 
 done:
 	initialization_debug(in);
@@ -792,15 +849,76 @@ done:
 }
 
 static void
-initialization_add_designator(initialization *in,
-			      const char *name, size_t subscript)
+initialization_add_designator_member(initialization *in, const char *name)
 {
+	brace_level *bl;
+	const type_t *tp;
+	const sym_t *member;
 
 	if (in->in_err)
 		return;
 
-	lint_assert(in->in_brace_level != NULL);
-	designation_add(&in->in_brace_level->bl_designation, name, subscript);
+	bl = in->in_brace_level;
+	lint_assert(bl != NULL);
+
+	tp = brace_level_sub_type(bl);
+	if (is_struct_or_union(tp->t_tspec))
+		goto proceed;
+	else if (tp->t_tspec == ARRAY) {
+		/* syntax error '%s' */
+		error(249, "designator '.member' is only for struct/union");
+		in->in_err = true;
+		return;
+	} else {
+		/* syntax error '%s' */
+		error(249, "scalar type cannot use designator");
+		in->in_err = true;
+		return;
+	}
+
+proceed:
+	member = look_up_member(tp, name);
+	if (member == NULL) {
+		/* type '%s' does not have member '%s' */
+		error(101, type_name(tp), name);
+		in->in_err = true;
+		return;
+	}
+
+	designation_push(&bl->bl_designation,
+	    tp->t_tspec == STRUCT ? DK_STRUCT : DK_UNION, member, 0);
+}
+
+static void
+initialization_add_designator_subscript(initialization *in, size_t subscript)
+{
+	brace_level *bl;
+	const type_t *tp;
+
+	if (in->in_err)
+		return;
+
+	bl = in->in_brace_level;
+	lint_assert(bl != NULL);
+
+	tp = brace_level_sub_type(bl);
+	if (tp->t_tspec != ARRAY) {
+		/* syntax error '%s' */
+		error(249, "designator '[...]' is only for arrays");
+		in->in_err = true;
+		return;
+	}
+
+	if (!tp->t_incomplete_array && subscript >= (size_t)tp->t_dim) {
+		/* array subscript cannot be > %d: %ld */
+		error(168, tp->t_dim - 1, (long)subscript);
+		subscript = 0;	/* suppress further errors */
+	}
+
+	if (tp->t_incomplete_array && subscript > in->in_max_subscript)
+		in->in_max_subscript = subscript;
+
+	designation_push(&bl->bl_designation, DK_ARRAY, NULL, subscript);
 }
 
 /*
@@ -836,42 +954,30 @@ initialization_init_array_from_string(in
 {
 	brace_level *bl;
 	const type_t *tp;
-	strg_t	*strg;
+	size_t len;
 
 	if (tn->tn_op != STRING)
 		return false;
 
-	bl = in->in_brace_level;
-	tp = initialization_sub_type(in, true);
-	strg = tn->tn_string;
-
-	if (!is_character_array(tp, strg->st_tspec)) {
-		/* TODO: recursively try first member or [0] */
-		if (is_struct_or_union(tp->t_tspec) ||
-		    (tp->t_tspec == ARRAY &&
-		     is_struct_or_union(tp->t_subt->t_tspec)))
-			in->in_err = true;
-		return false;
-	}
+	tp = initialization_sub_type(in);
 
-	if (bl != NULL && tp->t_tspec != ARRAY && bl->bl_subscript != 0)
+	if (!can_init_character_array(tp, tn))
 		return false;
 
-	if (!tp->t_incomplete_array && tp->t_dim < (int)strg->st_len) {
+	len = tn->tn_string->st_len;
+	if (!tp->t_incomplete_array && (size_t)tp->t_dim < len) {
 		/* string literal too long (%lu) for target array (%lu) */
-		warning(187,
-		    (unsigned long)strg->st_len, (unsigned long)tp->t_dim);
+		warning(187, (unsigned long)len, (unsigned long)tp->t_dim);
 	}
 
-	if (tp == in->in_sym->s_type && tp->t_incomplete_array) {
-		if (bl != NULL) {
-			bl->bl_subscript = strg->st_len;
-			/* see brace_level_advance for the +1 */
-			/* see initialization_set_size_of_unknown_array */
-		} else
-			update_type_of_array_of_unknown_size(in->in_sym,
-			    strg->st_len + 1);
-	}
+	bl = in->in_brace_level;
+	if (bl != NULL && bl->bl_designation.dn_len == 0)
+		designation_descend(&bl->bl_designation, bl->bl_type);
+	if (bl != NULL)
+		brace_level_advance(bl, &in->in_max_subscript);
+
+	if (tp == in->in_sym->s_type && tp->t_incomplete_array)
+		update_type_of_array_of_unknown_size(in->in_sym, len + 1);
 
 	return true;
 }
@@ -886,27 +992,25 @@ initialization_expr(initialization *in, 
 	brace_level *bl;
 	const type_t *tp;
 
-	if (in->in_err)
-		return;
-
-	bl = in->in_brace_level;
-	if (bl != NULL && bl->bl_confused)
+	if (in->in_err || tn == NULL)
 		return;
 
 	debug_enter();
 
-	if (tn == NULL)
-		goto advance;
+	bl = in->in_brace_level;
+	if (bl != NULL &&
+	    !brace_level_goto(bl, tn, &in->in_max_subscript)) {
+		in->in_err = true;
+		goto done;
+	}
 	if (initialization_expr_using_op(in, tn))
 		goto done;
 	if (initialization_init_array_from_string(in, tn))
-		goto advance;
+		goto done;
 	if (in->in_err)
 		goto done;
 
-	if (bl != NULL)
-		brace_level_apply_designation(bl);
-	tp = initialization_sub_type(in, false);
+	tp = initialization_sub_type(in);
 	if (tp == NULL)
 		goto done;
 
@@ -916,32 +1020,13 @@ initialization_expr(initialization *in, 
 		goto done;
 	}
 
-	/*
-	 * Hack to accept initializations with omitted braces, see
-	 * c99_6_7_8_p28_example5 in test d_c99_init.c.  Since both GCC and
-	 * Clang already warn about this at level -Wall, there is no point
-	 * in repeating the same check in lint.  If needed, support for these
-	 * edge cases could be added, but that would increase the complexity.
-	 */
-	if ((is_scalar(tn->tn_type->t_tspec) ||
-	     tn->tn_type->t_tspec == FUNC) &&
-	    (tp->t_tspec == ARRAY || is_struct_or_union(tp->t_tspec)) &&
-	    bl != NULL) {
-		bl->bl_confused = true;
-		goto done;
-	}
-
 	debug_step("expecting '%s', expression has '%s'",
 	    type_name(tp), type_name(tn->tn_type));
 	check_init_expr(tp, in->in_sym, tn);
-
-advance:
 	if (bl != NULL)
 		brace_level_advance(bl, &in->in_max_subscript);
-done:
-	if (bl != NULL)
-		designation_reset(&bl->bl_designation);
 
+done:
 	initialization_debug(in);
 	debug_leave();
 }
@@ -1000,21 +1085,22 @@ begin_designation(void)
 
 	bl = in->in_brace_level;
 	lint_assert(bl != NULL);
-	designation_reset(&bl->bl_designation);
+	bl->bl_designation.dn_len = 0;
+	designation_debug(&bl->bl_designation);
 }
 
 void
 add_designator_member(sbuf_t *sb)
 {
 
-	initialization_add_designator(current_init(), sb->sb_name, 0);
+	initialization_add_designator_member(current_init(), sb->sb_name);
 }
 
 void
 add_designator_subscript(range_t range)
 {
 
-	initialization_add_designator(current_init(), NULL, range.hi);
+	initialization_add_designator_subscript(current_init(), range.hi);
 }
 
 void

Reply via email to