Module Name: src
Committed By: rillig
Date: Sun Mar 28 10:52:41 UTC 2021
Modified Files:
src/usr.bin/xlint/lint1: init.c
Log Message:
lint: group functions according to their main object
No functional change.
To generate a diff of this commit:
cvs rdiff -u -r1.157 -r1.158 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/usr.bin/xlint/lint1/init.c
diff -u src/usr.bin/xlint/lint1/init.c:1.157 src/usr.bin/xlint/lint1/init.c:1.158
--- src/usr.bin/xlint/lint1/init.c:1.157 Sun Mar 28 10:09:34 2021
+++ src/usr.bin/xlint/lint1/init.c Sun Mar 28 10:52:41 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: init.c,v 1.157 2021/03/28 10:09:34 rillig Exp $ */
+/* $NetBSD: init.c,v 1.158 2021/03/28 10:52:41 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.157 2021/03/28 10:09:34 rillig Exp $");
+__RCSID("$NetBSD: init.c,v 1.158 2021/03/28 10:52:41 rillig Exp $");
#endif
#include <stdlib.h>
@@ -394,6 +394,85 @@ designation_shift_level(struct designati
}
+/* In traditional C, bit-fields can be initialized only by integer constants. */
+static void
+check_bit_field_init(const tnode_t *ln, tspec_t lt, tspec_t rt)
+{
+ if (tflag &&
+ is_integer(lt) &&
+ ln->tn_type->t_bitfield &&
+ !is_integer(rt)) {
+ /* bit-field initialization is illegal in traditional C */
+ warning(186);
+ }
+}
+
+static void
+check_non_constant_initializer(const tnode_t *tn, scl_t sclass)
+{
+ /* TODO: rename CON to CONSTANT to avoid ambiguity with CONVERT */
+ if (tn == NULL || tn->tn_op == CON)
+ return;
+
+ sym_t *sym;
+ ptrdiff_t offs;
+ if (constant_addr(tn, &sym, &offs))
+ return;
+
+ if (sclass == AUTO || sclass == REG) {
+ /* non-constant initializer */
+ c99ism(177);
+ } else {
+ /* non-constant initializer */
+ error(177);
+ }
+}
+
+static void
+check_init_expr(scl_t sclass, type_t *tp, sym_t *sym, tnode_t *tn)
+{
+ tnode_t *ln;
+ tspec_t lt, rt;
+ struct mbl *tmem;
+
+ /* Create a temporary node for the left side. */
+ ln = tgetblk(sizeof *ln);
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(tp);
+ ln->tn_type->t_const = false;
+ ln->tn_lvalue = true;
+ ln->tn_sym = sym;
+
+ tn = cconv(tn);
+
+ lt = ln->tn_type->t_tspec;
+ rt = tn->tn_type->t_tspec;
+
+ debug_step("typeok '%s', '%s'",
+ type_name(ln->tn_type), type_name(tn->tn_type));
+ if (!typeok(INIT, 0, ln, tn))
+ return;
+
+ /*
+ * Preserve the tree memory. This is necessary because otherwise
+ * expr() would free it.
+ */
+ tmem = tsave();
+ expr(tn, true, false, true, false);
+ trestor(tmem);
+
+ check_bit_field_init(ln, lt, rt);
+
+ /*
+ * XXX: Is it correct to do this conversion _after_ the typeok above?
+ */
+ if (lt != rt || (tp->t_bitfield && tn->tn_op == CON))
+ tn = convert(INIT, 0, tp, tn);
+
+ check_non_constant_initializer(tn, sclass);
+}
+
+
static struct brace_level *
brace_level_new(type_t *type, type_t *subtype, int remaining)
{
@@ -554,6 +633,50 @@ brace_level_push_array(struct brace_leve
return true;
}
+/*
+ * If the removed element was a structure member, we must go
+ * to the next structure member.
+ *
+ * XXX: Nothing should ever be "removed" at this point.
+ *
+ * TODO: think of a better name than 'pop'
+ */
+static void
+brace_level_pop_item_unnamed(struct brace_level *level)
+{
+ if (level->bl_remaining > 0 && level->bl_type->t_tspec == STRUCT &&
+ !level->bl_seen_named_member) {
+ brace_level_next_member(level);
+ level->bl_subtype = level->bl_next_member->s_type;
+ }
+}
+
+static bool
+brace_level_check_too_many_initializers(struct brace_level *level)
+{
+ if (level->bl_remaining > 0)
+ return true;
+ /*
+ * FIXME: even with named members, there can be too many initializers
+ */
+ if (level->bl_array_of_unknown_size || level->bl_seen_named_member)
+ return true;
+
+ tspec_t t = level->bl_type->t_tspec;
+ if (t == ARRAY) {
+ /* too many array initializers, expected %d */
+ error(173, level->bl_type->t_dim);
+ } else if (t == STRUCT || t == UNION) {
+ /* too many struct/union initializers */
+ error(172);
+ } else {
+ /* too many initializers */
+ error(174);
+ }
+ return false;
+}
+
+
static struct initialization *
initialization_new(sym_t *sym)
@@ -603,124 +726,15 @@ initialization_debug(const struct initia
#define initialization_debug(in) do { } while (false)
#endif
-static void
-initialization_set_error(struct initialization *in)
-{
- in->initerr = true;
-}
-
-/* XXX: unnecessary prototype since it is not recursive */
-static bool init_array_using_string(struct initialization *, tnode_t *);
-
-
-static struct initialization *
-current_init(void)
-{
- lint_assert(init != NULL);
- return init;
-}
-
-bool *
-current_initerr(void)
-{
- return ¤t_init()->initerr;
-}
-
-sym_t **
-current_initsym(void)
-{
- return ¤t_init()->initsym;
-}
-
-
-void
-begin_initialization(sym_t *sym)
-{
- struct initialization *in;
-
- debug_step("begin initialization of '%s'", type_name(sym->s_type));
- in = initialization_new(sym);
- in->next = init;
- init = in;
-}
-
-void
-end_initialization(void)
-{
- struct initialization *in;
-
- in = init;
- init = init->next;
- initialization_free(in);
- debug_step("end initialization");
-}
-
-void
-add_designator_member(sbuf_t *sb)
-{
- designation_add(¤t_init()->designation,
- designator_new(sb->sb_name));
-}
-
-/* TODO: Move the function body up here, to avoid the forward declaration. */
-static void initstack_pop_nobrace(struct initialization *);
-
-/*
- * A sub-object of an array is initialized using a designator. This does not
- * have to be an array element directly, it can also be used to initialize
- * only a sub-object of the array element.
- *
- * C99 example: struct { int member[4]; } var = { [2] = 12345 };
- *
- * GNU example: struct { int member[4]; } var = { [1 ... 3] = 12345 };
- *
- * TODO: test the following initialization with an outer and an inner type:
- *
- * .deeply[0].nested = {
- * .deeply[1].nested = {
- * 12345,
- * },
- * }
- */
-void
-add_designator_subscript(range_t range)
-{
- struct initialization *in = current_init();
- struct brace_level *level;
-
- debug_enter();
- if (range.lo == range.hi)
- debug_step("subscript is %zu", range.hi);
- else
- debug_step("subscript range is %zu ... %zu",
- range.lo, range.hi);
-
- /* XXX: This call is wrong here, it must be somewhere else. */
- initstack_pop_nobrace(in);
-
- level = in->brace_level;
- if (level->bl_array_of_unknown_size) {
- /* No +1 here, extend_if_array_of_unknown_size will add it. */
- int auto_dim = (int)range.hi;
- if (auto_dim > level->bl_type->t_dim)
- brace_level_set_array_dimension(level, auto_dim);
- }
-
- debug_leave();
-}
-
-
/*
* Initialize the initialization stack by putting an entry for the object
* which is to be initialized on it.
*
- * TODO: merge into begin_initialization
+ * TODO: merge into initialization_new if possible
*/
-void
-initstack_init(void)
+static void
+initialization_init(struct initialization *in)
{
- struct initialization *in = current_init();
-
if (in->initerr)
return;
@@ -740,135 +754,72 @@ initstack_init(void)
debug_leave();
}
-/* TODO: document me */
static void
-initstack_pop_item_named_member(struct initialization *in, const char *name)
+initialization_set_error(struct initialization *in)
{
- struct brace_level *level = in->brace_level;
- const sym_t *m;
+ in->initerr = true;
+}
+/* TODO: document me */
+/* TODO: think of a better name than 'push' */
+static bool
+initialization_push_struct_or_union(struct initialization *in)
+{
/*
- * TODO: fix wording of the debug message; this doesn't seem to be
- * related to initializing the named member.
+ * TODO: remove unnecessary 'const' for variables in functions that
+ * fit on a single screen. Keep it for larger functions.
*/
- debug_step("initializing named member '%s'", name);
+ struct brace_level *level = in->brace_level;
+ int cnt;
+ sym_t *m;
- if (level->bl_type->t_tspec != STRUCT &&
- level->bl_type->t_tspec != UNION) {
- /* syntax error '%s' */
- error(249, "named member must only be used with struct/union");
+ if (is_incomplete(level->bl_type)) {
+ /* initialization of an incomplete type */
+ error(175);
initialization_set_error(in);
- return;
+ return false;
}
- m = brace_level_look_up_member(level, name);
- if (m == NULL) {
- /* TODO: add type information to the message */
- /* undefined struct/union member: %s */
- error(101, name);
+ cnt = 0;
+ designation_debug(&in->designation);
+ debug_step("lookup for '%s'%s",
+ type_name(level->bl_type),
+ level->bl_seen_named_member ? ", seen named member" : "");
- designation_shift_level(&in->designation);
- level->bl_seen_named_member = true;
- return;
- }
-
- debug_step("found matching member");
- level->bl_subtype = m->s_type;
- /* XXX: why ++? */
- level->bl_remaining++;
- /* XXX: why is bl_seen_named_member not set? */
- designation_shift_level(&in->designation);
-}
-
-/* TODO: think of a better name than 'pop' */
-static void
-initstack_pop_item_unnamed(struct initialization *in)
-{
- struct brace_level *level = in->brace_level;
+ m = brace_level_look_up_member_bloated(level,
+ in->designation.head, &cnt);
- /*
- * If the removed element was a structure member, we must go
- * to the next structure member.
- */
- if (level->bl_remaining > 0 && level->bl_type->t_tspec == STRUCT &&
- !level->bl_seen_named_member) {
- brace_level_next_member(level);
- level->bl_subtype = level->bl_next_member->s_type;
+ if (in->designation.head != NULL) {
+ if (m == NULL) {
+ debug_step("pop struct");
+ return true;
+ }
+ level->bl_next_member = m;
+ level->bl_subtype = m->s_type;
+ level->bl_seen_named_member = true;
+ debug_step("named member '%s'",
+ in->designation.head->name);
+ designation_shift_level(&in->designation);
+ cnt = level->bl_type->t_tspec == STRUCT ? 2 : 1;
}
-}
-
-/* TODO: think of a better name than 'pop' */
-static void
-initstack_pop_item(struct initialization *in)
-{
- struct brace_level *level;
-
- debug_enter();
-
- level = in->brace_level;
- debug_indent();
- debug_printf("popping: ");
- brace_level_debug(level);
-
- in->brace_level = level->bl_enclosing;
- brace_level_free(level);
- level = in->brace_level;
- lint_assert(level != NULL);
-
- level->bl_remaining--;
- lint_assert(level->bl_remaining >= 0);
- debug_step("%d elements remaining", level->bl_remaining);
-
- if (in->designation.head != NULL && in->designation.head->name != NULL)
- initstack_pop_item_named_member(in, in->designation.head->name);
- else
- initstack_pop_item_unnamed(in);
-
- initialization_debug(in);
- debug_leave();
-}
-
-/*
- * Take all entries, including the first which requires a closing brace,
- * from the stack.
- */
-static void
-initstack_pop_brace(struct initialization *in)
-{
- bool brace;
-
- debug_enter();
- initialization_debug(in);
- do {
- brace = in->brace_level->bl_brace;
- /* TODO: improve wording of the debug message */
- debug_step("loop brace=%d", brace);
- initstack_pop_item(in);
- } while (!brace);
- initialization_debug(in);
- debug_leave();
-}
-
-/*
- * Take all entries which cannot be used for further initializers from the
- * stack, but do this only if they do not require a closing brace.
- */
-/* TODO: think of a better name than 'pop' */
-static void
-initstack_pop_nobrace(struct initialization *in)
-{
-
- debug_enter();
- while (!in->brace_level->bl_brace &&
- in->brace_level->bl_remaining == 0 &&
- !in->brace_level->bl_array_of_unknown_size)
- initstack_pop_item(in);
- debug_leave();
+ level->bl_brace = true;
+ debug_step("unnamed element with type '%s'%s",
+ type_name(
+ level->bl_type != NULL ? level->bl_type : level->bl_subtype),
+ level->bl_brace ? ", needs closing brace" : "");
+ if (cnt == 0) {
+ /* cannot init. struct/union with no named member */
+ error(179);
+ initialization_set_error(in);
+ return false;
+ }
+ level->bl_remaining = level->bl_type->t_tspec == STRUCT ? cnt : 1;
+ return false;
}
/* Extend an array of unknown size by one element */
static void
-extend_if_array_of_unknown_size(struct initialization *in)
+initialization_extend_if_array_of_unknown_size(struct initialization *in)
{
struct brace_level *level = in->brace_level;
@@ -896,80 +847,21 @@ extend_if_array_of_unknown_size(struct i
debug_step("extended type is '%s'", type_name(level->bl_type));
}
-
-
-/* TODO: document me */
-/* TODO: think of a better name than 'push' */
-static bool
-initstack_push_struct_or_union(struct initialization *in)
-{
- /*
- * TODO: remove unnecessary 'const' for variables in functions that
- * fit on a single screen. Keep it for larger functions.
- */
- struct brace_level *level = in->brace_level;
- int cnt;
- sym_t *m;
-
- if (is_incomplete(level->bl_type)) {
- /* initialization of an incomplete type */
- error(175);
- initialization_set_error(in);
- return false;
- }
-
- cnt = 0;
- designation_debug(&in->designation);
- debug_step("lookup for '%s'%s",
- type_name(level->bl_type),
- level->bl_seen_named_member ? ", seen named member" : "");
-
- m = brace_level_look_up_member_bloated(level,
- in->designation.head, &cnt);
-
- if (in->designation.head != NULL) {
- if (m == NULL) {
- debug_step("pop struct");
- return true;
- }
- level->bl_next_member = m;
- level->bl_subtype = m->s_type;
- level->bl_seen_named_member = true;
- debug_step("named member '%s'",
- in->designation.head->name);
- designation_shift_level(&in->designation);
- cnt = level->bl_type->t_tspec == STRUCT ? 2 : 1;
- }
- level->bl_brace = true;
- debug_step("unnamed element with type '%s'%s",
- type_name(
- level->bl_type != NULL ? level->bl_type : level->bl_subtype),
- level->bl_brace ? ", needs closing brace" : "");
- if (cnt == 0) {
- /* cannot init. struct/union with no named member */
- error(179);
- initialization_set_error(in);
- return false;
- }
- level->bl_remaining = level->bl_type->t_tspec == STRUCT ? cnt : 1;
- return false;
-}
-
/* TODO: document me */
/* TODO: think of a better name than 'push' */
static void
-initstack_push(struct initialization *in)
+initialization_push(struct initialization *in)
{
struct brace_level *level, *enclosing;
debug_enter();
- extend_if_array_of_unknown_size(in);
+ initialization_extend_if_array_of_unknown_size(in);
level = in->brace_level;
lint_assert(level->bl_remaining > 0);
lint_assert(level->bl_type == NULL ||
- !is_scalar(level->bl_type->t_tspec));
+ !is_scalar(level->bl_type->t_tspec));
in->brace_level = xcalloc(1, sizeof *in->brace_level);
in->brace_level->bl_enclosing = level;
@@ -1000,13 +892,13 @@ again:
warning(238);
/* FALLTHROUGH */
case STRUCT:
- if (initstack_push_struct_or_union(in))
+ if (initialization_push_struct_or_union(in))
goto pop;
break;
default:
if (in->designation.head != NULL) {
debug_step("pop scalar");
- pop:
+ pop:
/* TODO: extract this into end_initializer_level */
enclosing = in->brace_level->bl_enclosing;
brace_level_free(level);
@@ -1022,31 +914,92 @@ again:
debug_leave();
}
+/* TODO: document me */
static void
-check_too_many_initializers(struct initialization *in)
+initialization_pop_item_named(struct initialization *in, const char *name)
{
- const struct brace_level *level = in->brace_level;
+ struct brace_level *level = in->brace_level;
+ const sym_t *m;
- if (level->bl_remaining > 0)
- return;
/*
- * FIXME: even with named members, there can be too many initializers
+ * TODO: fix wording of the debug message; this doesn't seem to be
+ * related to initializing the named member.
*/
- if (level->bl_array_of_unknown_size || level->bl_seen_named_member)
+ debug_step("initializing named member '%s'", name);
+
+ if (level->bl_type->t_tspec != STRUCT &&
+ level->bl_type->t_tspec != UNION) {
+ /* syntax error '%s' */
+ error(249, "named member must only be used with struct/union");
+ initialization_set_error(in);
return;
+ }
- tspec_t t = level->bl_type->t_tspec;
- if (t == ARRAY) {
- /* too many array initializers, expected %d */
- error(173, level->bl_type->t_dim);
- } else if (t == STRUCT || t == UNION) {
- /* too many struct/union initializers */
- error(172);
- } else {
- /* too many initializers */
- error(174);
+ m = brace_level_look_up_member(level, name);
+ if (m == NULL) {
+ /* TODO: add type information to the message */
+ /* undefined struct/union member: %s */
+ error(101, name);
+
+ designation_shift_level(&in->designation);
+ level->bl_seen_named_member = true;
+ return;
}
- initialization_set_error(in);
+
+ debug_step("found matching member");
+ level->bl_subtype = m->s_type;
+ /* XXX: why ++? */
+ level->bl_remaining++;
+ /* XXX: why is bl_seen_named_member not set? */
+ designation_shift_level(&in->designation);
+}
+
+/* TODO: think of a better name than 'pop' */
+static void
+initialization_pop_item(struct initialization *in)
+{
+ struct brace_level *level;
+
+ debug_enter();
+
+ level = in->brace_level;
+ debug_indent();
+ debug_printf("popping: ");
+ brace_level_debug(level);
+
+ in->brace_level = level->bl_enclosing;
+ brace_level_free(level);
+ level = in->brace_level;
+ lint_assert(level != NULL);
+
+ level->bl_remaining--;
+ lint_assert(level->bl_remaining >= 0);
+ debug_step("%d elements remaining", level->bl_remaining);
+
+ if (in->designation.head != NULL && in->designation.head->name != NULL)
+ initialization_pop_item_named(in, in->designation.head->name);
+ else
+ brace_level_pop_item_unnamed(level);
+
+ initialization_debug(in);
+ debug_leave();
+}
+
+/*
+ * Take all entries which cannot be used for further initializers from the
+ * stack, but do this only if they do not require a closing brace.
+ */
+/* TODO: think of a better name than 'pop' */
+static void
+initialization_pop_nobrace(struct initialization *in)
+{
+
+ debug_enter();
+ while (!in->brace_level->bl_brace &&
+ in->brace_level->bl_remaining == 0 &&
+ !in->brace_level->bl_array_of_unknown_size)
+ initialization_pop_item(in);
+ debug_leave();
}
/*
@@ -1055,7 +1008,7 @@ check_too_many_initializers(struct initi
* initialization level.
*/
static void
-initstack_next_brace(struct initialization *in)
+initialization_next_brace(struct initialization *in)
{
debug_enter();
@@ -1067,10 +1020,14 @@ initstack_next_brace(struct initializati
error(176, type_name(in->brace_level->bl_type));
initialization_set_error(in);
}
+
+ if (!in->initerr &&
+ !brace_level_check_too_many_initializers(in->brace_level))
+ initialization_set_error(in);
+
if (!in->initerr)
- check_too_many_initializers(in);
- if (!in->initerr)
- initstack_push(in);
+ initialization_push(in);
+
if (!in->initerr) {
in->brace_level->bl_brace = true;
designation_debug(&in->designation);
@@ -1084,50 +1041,9 @@ initstack_next_brace(struct initializati
debug_leave();
}
-/* TODO: document me, or think of a better name */
static void
-initstack_next_nobrace(struct initialization *in, tnode_t *tn)
-{
- debug_enter();
-
- if (in->brace_level->bl_type == NULL &&
- !is_scalar(in->brace_level->bl_subtype->t_tspec)) {
- /* {}-enclosed initializer required */
- error(181);
- /* XXX: maybe set initerr here */
- }
-
- if (!in->initerr)
- check_too_many_initializers(in);
-
- while (!in->initerr) {
- struct brace_level *level = in->brace_level;
-
- if (tn->tn_type->t_tspec == STRUCT &&
- level->bl_type == tn->tn_type &&
- level->bl_enclosing != NULL &&
- level->bl_enclosing->bl_enclosing != NULL) {
- level->bl_brace = false;
- level->bl_remaining = 1; /* the struct itself */
- break;
- }
-
- if (level->bl_type != NULL &&
- is_scalar(level->bl_type->t_tspec))
- break;
- initstack_push(in);
- }
-
- initialization_debug(in);
- debug_leave();
-}
-
-/* TODO: document me */
-void
-init_lbrace(void)
+initialization_lbrace(struct initialization *in)
{
- struct initialization *in = current_init();
-
if (in->initerr)
return;
@@ -1146,9 +1062,9 @@ init_lbrace(void)
* Remove all entries which cannot be used for further initializers
* and do not expect a closing brace.
*/
- initstack_pop_nobrace(in);
+ initialization_pop_nobrace(in);
- initstack_next_brace(in);
+ initialization_next_brace(in);
initialization_debug(in);
debug_leave();
@@ -1157,176 +1073,76 @@ init_lbrace(void)
/*
* Process a '}' in an initializer by finishing the current level of the
* initialization stack.
+ *
+ * Take all entries, including the first which requires a closing brace,
+ * from the stack.
*/
-void
-init_rbrace(void)
+static void
+initialization_rbrace(struct initialization *in)
{
- struct initialization *in = current_init();
+ bool brace;
if (in->initerr)
return;
debug_enter();
- initstack_pop_brace(in);
+ do {
+ brace = in->brace_level->bl_brace;
+ /* TODO: improve wording of the debug message */
+ debug_step("loop brace=%d", brace);
+ initialization_pop_item(in);
+ } while (!brace);
+ initialization_debug(in);
debug_leave();
}
-/* In traditional C, bit-fields can be initialized only by integer constants. */
-static void
-check_bit_field_init(const tnode_t *ln, tspec_t lt, tspec_t rt)
-{
- if (tflag &&
- is_integer(lt) &&
- ln->tn_type->t_bitfield &&
- !is_integer(rt)) {
- /* bit-field initialization is illegal in traditional C */
- warning(186);
- }
-}
-
-static void
-check_non_constant_initializer(const tnode_t *tn, scl_t sclass)
-{
- /* TODO: rename CON to CONSTANT to avoid ambiguity with CONVERT */
- if (tn == NULL || tn->tn_op == CON)
- return;
-
- sym_t *sym;
- ptrdiff_t offs;
- if (constant_addr(tn, &sym, &offs))
- return;
-
- if (sclass == AUTO || sclass == REG) {
- /* non-constant initializer */
- c99ism(177);
- } else {
- /* non-constant initializer */
- error(177);
- }
-}
-
/*
- * Initialize a non-array object with automatic storage duration and only a
- * single initializer expression without braces by delegating to ASSIGN.
+ * A sub-object of an array is initialized using a designator. This does not
+ * have to be an array element directly, it can also be used to initialize
+ * only a sub-object of the array element.
+ *
+ * C99 example: struct { int member[4]; } var = { [2] = 12345 };
+ *
+ * GNU example: struct { int member[4]; } var = { [1 ... 3] = 12345 };
+ *
+ * TODO: test the following initialization with an outer and an inner type:
+ *
+ * .deeply[0].nested = {
+ * .deeply[1].nested = {
+ * 12345,
+ * },
+ * }
*/
-static bool
-init_using_assign(struct initialization *in, tnode_t *rn)
-{
- tnode_t *ln, *tn;
-
- if (in->initsym->s_type->t_tspec == ARRAY)
- return false;
- if (in->brace_level->bl_enclosing != NULL)
- return false;
-
- debug_step("handing over to ASSIGN");
-
- ln = new_name_node(in->initsym, 0);
- ln->tn_type = tduptyp(ln->tn_type);
- ln->tn_type->t_const = false;
-
- tn = build(ASSIGN, ln, rn);
- expr(tn, false, false, false, false);
-
- /* XXX: why not clean up the initstack here already? */
- return true;
-}
-
static void
-check_init_expr(struct initialization *in, tnode_t *tn, scl_t sclass)
+initialization_add_designator_subscript(struct initialization *in,
+ range_t range)
{
- tnode_t *ln;
- tspec_t lt, rt;
- struct mbl *tmem;
-
- /* Create a temporary node for the left side. */
- ln = tgetblk(sizeof *ln);
- ln->tn_op = NAME;
- ln->tn_type = tduptyp(in->brace_level->bl_type);
- ln->tn_type->t_const = false;
- ln->tn_lvalue = true;
- ln->tn_sym = in->initsym; /* better than nothing */
-
- tn = cconv(tn);
-
- lt = ln->tn_type->t_tspec;
- rt = tn->tn_type->t_tspec;
-
- debug_step("typeok '%s', '%s'",
- type_name(ln->tn_type), type_name(tn->tn_type));
- if (!typeok(INIT, 0, ln, tn))
- return;
-
- /*
- * Preserve the tree memory. This is necessary because otherwise
- * expr() would free it.
- */
- tmem = tsave();
- expr(tn, true, false, true, false);
- trestor(tmem);
-
- check_bit_field_init(ln, lt, rt);
-
- /*
- * XXX: Is it correct to do this conversion _after_ the typeok above?
- */
- if (lt != rt ||
- (in->brace_level->bl_type->t_bitfield && tn->tn_op == CON))
- tn = convert(INIT, 0, in->brace_level->bl_type, tn);
-
- check_non_constant_initializer(tn, sclass);
-}
-
-void
-init_using_expr(tnode_t *tn)
-{
- struct initialization *in = current_init();
- scl_t sclass;
+ struct brace_level *level;
debug_enter();
- initialization_debug(in);
- designation_debug(&in->designation);
- debug_step("expr:");
- debug_node(tn, debug_ind + 1);
-
- if (in->initerr || tn == NULL)
- goto done;
-
- sclass = in->initsym->s_scl;
- if ((sclass == AUTO || sclass == REG) && init_using_assign(in, tn))
- goto done;
+ if (range.lo == range.hi)
+ debug_step("subscript is %zu", range.hi);
+ else
+ debug_step("subscript range is %zu ... %zu",
+ range.lo, range.hi);
- initstack_pop_nobrace(in);
+ /* XXX: This call is wrong here, it must be somewhere else. */
+ initialization_pop_nobrace(in);
- if (init_array_using_string(in, tn)) {
- debug_step("after initializing the string:");
- /* XXX: why not clean up the initstack here already? */
- goto done_initstack;
+ level = in->brace_level;
+ if (level->bl_array_of_unknown_size) {
+ /* No +1 here, extend_if_array_of_unknown_size will add it. */
+ int auto_dim = (int)range.hi;
+ if (auto_dim > level->bl_type->t_dim)
+ brace_level_set_array_dimension(level, auto_dim);
}
- initstack_next_nobrace(in, tn);
- if (in->initerr || tn == NULL)
- goto done_initstack;
-
- in->brace_level->bl_remaining--;
- debug_step("%d elements remaining", in->brace_level->bl_remaining);
-
- check_init_expr(in, tn, sclass);
-
-done_initstack:
- initialization_debug(in);
-
-done:
- while (in->designation.head != NULL)
- designation_shift_level(&in->designation);
-
debug_leave();
}
-
/* Initialize a character array or wchar_t array with a string literal. */
static bool
-init_array_using_string(struct initialization *in, tnode_t *tn)
+initialization_init_array_using_string(struct initialization *in, tnode_t *tn)
{
tspec_t t;
struct brace_level *level;
@@ -1358,7 +1174,7 @@ init_array_using_string(struct initializ
/* XXX: duplicate code, see below */
/* Put the array at top of stack */
- initstack_push(in);
+ initialization_push(in);
level = in->brace_level;
/* TODO: what if both bl_type and bl_subtype are ARRAY? */
@@ -1423,3 +1239,194 @@ init_array_using_string(struct initializ
debug_leave();
return true;
}
+
+/*
+ * Initialize a non-array object with automatic storage duration and only a
+ * single initializer expression without braces by delegating to ASSIGN.
+ */
+static bool
+initialization_init_using_assign(struct initialization *in, tnode_t *rn)
+{
+ tnode_t *ln, *tn;
+
+ if (in->initsym->s_type->t_tspec == ARRAY)
+ return false;
+ if (in->brace_level->bl_enclosing != NULL)
+ return false;
+
+ debug_step("handing over to ASSIGN");
+
+ ln = new_name_node(in->initsym, 0);
+ ln->tn_type = tduptyp(ln->tn_type);
+ ln->tn_type->t_const = false;
+
+ tn = build(ASSIGN, ln, rn);
+ expr(tn, false, false, false, false);
+
+ /* XXX: why not clean up the initstack here already? */
+ return true;
+}
+
+/* TODO: document me, or think of a better name */
+static void
+initialization_next_nobrace(struct initialization *in, tnode_t *tn)
+{
+ debug_enter();
+
+ if (in->brace_level->bl_type == NULL &&
+ !is_scalar(in->brace_level->bl_subtype->t_tspec)) {
+ /* {}-enclosed initializer required */
+ error(181);
+ /* XXX: maybe set initerr here */
+ }
+
+ if (!in->initerr &&
+ !brace_level_check_too_many_initializers(in->brace_level))
+ initialization_set_error(in);
+
+ while (!in->initerr) {
+ struct brace_level *level = in->brace_level;
+
+ if (tn->tn_type->t_tspec == STRUCT &&
+ level->bl_type == tn->tn_type &&
+ level->bl_enclosing != NULL &&
+ level->bl_enclosing->bl_enclosing != NULL) {
+ level->bl_brace = false;
+ level->bl_remaining = 1; /* the struct itself */
+ break;
+ }
+
+ if (level->bl_type != NULL &&
+ is_scalar(level->bl_type->t_tspec))
+ break;
+ initialization_push(in);
+ }
+
+ initialization_debug(in);
+ debug_leave();
+}
+
+static void
+initialization_expr(struct initialization *in, tnode_t *tn)
+{
+ scl_t sclass;
+
+ debug_enter();
+ initialization_debug(in);
+ designation_debug(&in->designation);
+ debug_step("expr:");
+ debug_node(tn, debug_ind + 1);
+
+ if (in->initerr || tn == NULL)
+ goto done;
+
+ sclass = in->initsym->s_scl;
+ if ((sclass == AUTO || sclass == REG) &&
+ initialization_init_using_assign(in, tn))
+ goto done;
+
+ initialization_pop_nobrace(in);
+
+ if (initialization_init_array_using_string(in, tn)) {
+ debug_step("after initializing the string:");
+ /* XXX: why not clean up the initstack here already? */
+ goto done_initstack;
+ }
+
+ initialization_next_nobrace(in, tn);
+ if (in->initerr || tn == NULL)
+ goto done_initstack;
+
+ in->brace_level->bl_remaining--;
+ debug_step("%d elements remaining", in->brace_level->bl_remaining);
+
+ /* Using initsym here is better than nothing. */
+ check_init_expr(sclass, in->brace_level->bl_type, in->initsym, tn);
+
+done_initstack:
+ initialization_debug(in);
+
+done:
+ while (in->designation.head != NULL)
+ designation_shift_level(&in->designation);
+
+ debug_leave();
+}
+
+static struct initialization *
+current_init(void)
+{
+ lint_assert(init != NULL);
+ return init;
+}
+
+bool *
+current_initerr(void)
+{
+ return ¤t_init()->initerr;
+}
+
+sym_t **
+current_initsym(void)
+{
+ return ¤t_init()->initsym;
+}
+
+void
+begin_initialization(sym_t *sym)
+{
+ struct initialization *in;
+
+ debug_step("begin initialization of '%s'", type_name(sym->s_type));
+ in = initialization_new(sym);
+ in->next = init;
+ init = in;
+}
+
+void
+end_initialization(void)
+{
+ struct initialization *in;
+
+ in = init;
+ init = init->next;
+ initialization_free(in);
+ debug_step("end initialization");
+}
+
+void
+add_designator_member(sbuf_t *sb)
+{
+ designation_add(¤t_init()->designation,
+ designator_new(sb->sb_name));
+}
+
+void
+add_designator_subscript(range_t range)
+{
+ initialization_add_designator_subscript(current_init(), range);
+}
+
+void
+initstack_init(void)
+{
+ initialization_init(current_init());
+}
+
+void
+init_lbrace(void)
+{
+ initialization_lbrace(current_init());
+}
+
+void
+init_using_expr(tnode_t *tn)
+{
+ initialization_expr(current_init(), tn);
+}
+
+void
+init_rbrace(void)
+{
+ initialization_rbrace(current_init());
+}