Signed-off-by: Jose E. Marchesi <[email protected]>
gcc/ChangeLog
* algol68/a68-low-moids.cc: New file.
---
gcc/algol68/a68-low-moids.cc | 729 +++++++++++++++++++++++++++++++++++
1 file changed, 729 insertions(+)
create mode 100644 gcc/algol68/a68-low-moids.cc
diff --git a/gcc/algol68/a68-low-moids.cc b/gcc/algol68/a68-low-moids.cc
new file mode 100644
index 00000000000..4dbf1189162
--- /dev/null
+++ b/gcc/algol68/a68-low-moids.cc
@@ -0,0 +1,729 @@
+/* Lower Algol 68 modes to GCC trees.
+ Copyright (C) 2025 Jose E. Marchesi.
+
+ Written by Jose E. Marchesi.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#define INCLUDE_MEMORY
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+#include "tree.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "predict.h"
+#include "stor-layout.h"
+#include "print-tree.h"
+
+#include "a68.h"
+
+static tree a68_lower_mode (MOID_T *m);
+
+/*
+ * Support routines and definitions.
+ */
+
+/* Build a stub TYPE_DECL for a given TYPE.
+
+ This is used for TYPE_STUB_DECL so we can generate debug info for all our
+ modes, so the TYPE_DECL has no name. */
+
+static void
+build_stub_type_decl (tree type, tree context)
+{
+ if (TYPE_STUB_DECL (type))
+ return;
+
+ tree decl = build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
+ NULL_TREE /* name */,
+ type);
+ TREE_PUBLIC (decl) = 1;
+ DECL_CONTEXT (decl) = context;
+ TYPE_CONTEXT (type) = DECL_CONTEXT (decl);
+ TYPE_NAME (type) = decl; /* Weird. This is for typedefs! */
+ TYPE_STUB_DECL (type) = decl;
+}
+
+/* Builds a record type whose name is NAME. NFIELDS is the number of fields,
+ provided as field ident/type pairs.
+
+ This code is copied from the D front end. */
+
+static tree
+make_struct_type (tree type, const char *name, int nfields, ...)
+{
+ tree fields = NULL_TREE;
+ va_list ap;
+
+ va_start (ap, nfields);
+
+ for (int i = 0; i < nfields; i++)
+ {
+ tree ident = va_arg (ap, tree);
+ tree type = va_arg (ap, tree);
+ tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, ident, type);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+ }
+
+ va_end (ap);
+
+ if (type == NULL_TREE)
+ type = make_node (RECORD_TYPE);
+ finish_builtin_struct (type, name, fields, NULL_TREE);
+
+ return type;
+}
+
+/* Iterate over all the field selectors FIELDS of a structure type and add them
+ as fields to CONTEXT. Returns the number of field selectors found. */
+
+static size_t
+chain_struct_fields (PACK_T *fields, tree context)
+{
+ PACK_T *elem;
+ size_t num_fields;
+
+ for (num_fields = 0, elem = fields;
+ elem != NO_PACK;
+ FORWARD (elem), ++num_fields)
+ {
+ const char *field_name = TEXT (elem);
+ MOID_T *field_mode = MOID (elem);
+ tree field_type = a68_lower_mode (field_mode);
+
+ /* Create the field declaration.
+ The declaration is not a compiler-generated entity.
+ Do not ignore the declaration for symbolic debug purposes. */
+ tree field_decl = build_decl ((NODE (field_mode)
+ ? a68_get_node_location (NODE (field_mode))
+ : UNKNOWN_LOCATION),
+ FIELD_DECL,
+ field_name ? get_identifier (field_name) :
NULL_TREE,
+ field_type);
+ DECL_ARTIFICIAL (field_decl) = 0;
+ DECL_IGNORED_P (field_decl) = 0;
+
+ /* If the mode of the field is not a ref then references to the field
+ cannot appear in a LHS of an assignment. */
+ TREE_READONLY (field_decl) = IS_REF (field_mode);
+
+ /* Associate the tree field declaration and the front end node. */
+ DECL_LANG_SPECIFIC (field_decl) =
+ (NODE (field_mode) ? a68_build_lang_decl (NODE (field_mode)) : NULL);
+
+ /* Chain the field declaration in its containing context. */
+ DECL_FIELD_CONTEXT (field_decl) = context;
+ TYPE_FIELDS (context) = chainon (TYPE_FIELDS (context), field_decl);
+ }
+
+ return num_fields;
+}
+
+/* If the union or struct type TYPE completes the type of any previous field
+ declarations, lay them out now. */
+
+static void
+finish_incomplete_fields (tree type)
+{
+ for (tree fwdref = TYPE_FORWARD_REFERENCES (type); fwdref != NULL_TREE;
+ fwdref = TREE_CHAIN (fwdref))
+ {
+ tree field = TREE_VALUE (fwdref);
+ tree struct_or_union_type = DECL_FIELD_CONTEXT (field);
+
+ relayout_decl (field);
+ bool type_complete = true;
+ for (tree field = TYPE_FIELDS (struct_or_union_type);
+ field;
+ field = DECL_CHAIN (field))
+ {
+ if (!COMPLETE_TYPE_P (TREE_TYPE (field)))
+ {
+ type_complete = false;
+ break;
+ }
+ }
+
+ if (type_complete)
+ {
+ // XXX why this fires
+ // gcc_assert (!COMPLETE_TYPE_P (struct_or_union_type));
+ layout_type (struct_or_union_type);
+ /* Set the back-end type mode now that all fields have had their size
+ set. */
+ compute_record_mode (struct_or_union_type);
+ }
+ };
+
+ /* No more forward references to process. */
+ TYPE_FORWARD_REFERENCES (type) = NULL_TREE;
+}
+
+/*
+ * Mode lowering routines.
+ */
+
+/* Lower a HIP mode to a GENERIC tree.
+ HIP is the mode of NIL. */
+
+static tree
+lower_hip_mode (MOID_T *m)
+{
+ static tree hip_type;
+
+ if (hip_type == NULL)
+ {
+ hip_type = build_pointer_type (a68_void_type);
+ TYPE_LANG_SPECIFIC (hip_type) = a68_build_lang_type (m);
+ CTYPE (m) = hip_type;
+ }
+
+ return hip_type;
+}
+
+/* Lower a standard mode to a GENERIC tree.
+
+ Note that this function only has to handle the standard modes that have not
+ been resolved to some equivalent. */
+
+static tree
+lower_standard_mode (MOID_T *m)
+{
+ tree type = NULL_TREE;
+
+ if (m == M_VOID)
+ type = a68_void_type;
+ else if (m == M_BOOL)
+ type = a68_bool_type;
+ else if (m == M_CHAR)
+ type = a68_char_type;
+ else if (m == M_SHORT_SHORT_INT)
+ type = a68_short_short_int_type;
+ else if (m == M_SHORT_INT)
+ type = a68_short_int_type;
+ else if (m == M_INT)
+ type = a68_int_type;
+ else if (m == M_LONG_INT)
+ type = a68_long_int_type;
+ else if (m == M_LONG_LONG_INT)
+ type = a68_long_long_int_type;
+ else if (m == M_REAL)
+ type = a68_real_type;
+ else if (m == M_LONG_REAL)
+ type = a68_long_real_type;
+ else if (m == M_LONG_LONG_REAL)
+ type = a68_long_long_real_type;
+ else if (m == M_SHORT_SHORT_BITS)
+ type = a68_short_short_bits_type;
+ else if (m == M_SHORT_BITS)
+ type = a68_short_bits_type;
+ else if (m == M_BITS)
+ type = a68_bits_type;
+ else if (m == M_LONG_BITS)
+ type = a68_long_bits_type;
+ else if (m == M_LONG_LONG_BITS)
+ type = a68_long_long_bits_type;
+ else if (m == M_BYTES)
+ type = a68_bytes_type;
+ else if (m == M_LONG_BYTES)
+ type = a68_long_bytes_type;
+ else if (m == M_FILE)
+ /* XXX for now this is a file descriptor. */
+ type = integer_type_node;
+ else if (m == M_CHANNEL)
+ /* XXX for now this is a channel descriptor. */
+ type = integer_type_node;
+ else
+ gcc_unreachable ();
+
+ TYPE_LANG_SPECIFIC (type) = a68_build_lang_type (m);
+ return type;
+}
+
+/* Lower a struct mode to a GENERIC tree. */
+
+static tree
+lower_struct_mode (MOID_T *m)
+{
+ /* First make the GENERIC struct. This is needed in case of
+ self-references. */
+ tree struct_type = make_node (RECORD_TYPE);
+ TYPE_NAME (struct_type) = get_identifier ("lalastruct%");
+ TYPE_FIELDS (struct_type) = NULL_TREE;
+ TYPE_CXX_ODR_P (struct_type) = 0;
+ CTYPE (m) = struct_type;
+ TYPE_LANG_SPECIFIC (struct_type) = a68_build_lang_type (m); /* XXX this will
get overrided. */
+
+ /* Add field declarations. */
+ chain_struct_fields (PACK (m), struct_type);
+
+ /* Layout all fields. */
+ bool struct_type_complete = true;
+ for (tree field = TYPE_FIELDS (struct_type); field; field = DECL_CHAIN
(field))
+ {
+ tree basetype = TREE_TYPE (field);
+
+ if (!COMPLETE_TYPE_P (basetype))
+ {
+ tree field_type = TREE_TYPE (field);
+ tree forward_refs = tree_cons (NULL_TREE, field,
+ TYPE_FORWARD_REFERENCES (field_type));
+ TYPE_FORWARD_REFERENCES (struct_type) = forward_refs;
+
+ struct_type_complete = false;
+ continue;
+ }
+
+ layout_decl (field, 0);
+ gcc_assert (DECL_SIZE (field) != NULL_TREE);
+ }
+
+ /* If all fields have complete types then we can layout the struct type now.
+ Otherwise it will be done in finish_incomplete_types. */
+ if (struct_type_complete)
+ {
+ layout_type (struct_type);
+ /* Set the back-end type mode now that all fields have had their size
+ set. */
+ compute_record_mode (struct_type);
+ }
+
+ /* Finish debugging output for this type. */
+ build_stub_type_decl (struct_type, NULL_TREE /* context */);
+ rest_of_type_compilation (struct_type, TYPE_FILE_SCOPE_P (struct_type));
+ rest_of_decl_compilation (TYPE_NAME (struct_type), 1 /* file scope p */, 0);
+ A68_STRUCT_TYPE_P (struct_type) = 1;
+ return struct_type;
+}
+
+/* Lower a ref mode to a GENERIC tree.
+ REF AMODE lowers to a pointer. */
+
+static tree
+lower_ref_mode (MOID_T *m)
+{
+ return build_pointer_type (a68_lower_mode (SUB (m)));
+}
+
+/* Lower a flex mode to a GENERIC tree. */
+
+static tree
+lower_flex_mode (MOID_T *m)
+{
+ /* This is basically a qualifier of the parent REF. */
+ return a68_lower_mode (SUB (m));
+}
+
+/* Lower a proc mode to a GENERIC tree. */
+
+static tree
+lower_proc_mode (MOID_T *m)
+{
+ tree fnargs = NULL_TREE;
+ tree ret_type;
+
+ /* We have to create the function type in advance because it can appear
+ recursively as the type of arguments and/or of the return value. We
+ cannot use build_function_type, as it doesn't support recursive types. */
+ tree function_type = make_node (FUNCTION_TYPE);
+ tree ptr_function_type = build_pointer_type (function_type);
+ CTYPE (m) = ptr_function_type;
+
+ /* Now add arguments and return value types. */
+ for (PACK_T *p = PACK (m); p != NO_PACK; FORWARD (p))
+ {
+ tree arg_type = a68_lower_mode (MOID (p));
+ fnargs = chainon (fnargs, build_tree_list (0, arg_type));
+ }
+ ret_type = a68_lower_mode (SUB (m));
+
+ /* Complete the function type. Note that there is some code duplication with
+ build_function_type, which we cannot use, but such is life. */
+ TREE_TYPE (function_type) = ret_type; /* THIS */
+ TYPE_ARG_TYPES (function_type) = fnargs;
+ SET_TYPE_STRUCTURAL_EQUALITY (function_type);
+
+ if (!COMPLETE_TYPE_P (function_type))
+ layout_type (function_type);
+
+ return ptr_function_type;
+}
+
+/* Lower an union mode to a GENERIC tree.
+
+ overhead% Characterizes the actual mode of the value.
+ value% GENERIC union. */
+
+static tree
+lower_union_mode (MOID_T *m)
+{
+ // XXX make the union type QUAL_UNION_TYPE and relate the fields with the
+ // overhead%. This is necessary for DWARF.
+ tree union_type = make_node (RECORD_TYPE);
+ TYPE_NAME (union_type) = NULL_TREE;
+ TYPE_FIELDS (union_type) = NULL_TREE;
+ TYPE_CXX_ODR_P (union_type) = 0;
+ CTYPE (m) = union_type;
+
+ /* Then the GENERIC union. */
+ tree c_union_type = make_node (UNION_TYPE);
+ TYPE_NAME (c_union_type) = NULL_TREE;
+ TYPE_FIELDS (c_union_type) = NULL_TREE;
+ TYPE_CXX_ODR_P (c_union_type) = 0; // XXX otherwise lto complains. why.
+ SET_TYPE_STRUCTURAL_EQUALITY (c_union_type);
+
+ /* Add field declarations. */
+ chain_struct_fields (PACK (m), c_union_type);
+
+ /* Layout all fields now the type is complete. */
+ bool c_union_type_complete = true;
+ for (tree field = TYPE_FIELDS (c_union_type); field; field = DECL_CHAIN
(field))
+ {
+ tree field_type = TREE_TYPE (field);
+
+ if (!COMPLETE_TYPE_P (field_type))
+ {
+ tree field_type = TREE_TYPE (field);
+ tree forward_refs = tree_cons (NULL_TREE, field,
+ TYPE_FORWARD_REFERENCES (field_type));
+ TYPE_FORWARD_REFERENCES (c_union_type) = forward_refs;
+
+ c_union_type_complete = false;
+ continue;
+ }
+
+ layout_decl (field, 0);
+ gcc_assert (DECL_SIZE (field) != NULL_TREE);
+ }
+
+ /* If all fields have complete types then we can layout the c-union type now.
+ Otherwise it will be done in finish_incomplete_types. */
+ if (c_union_type_complete)
+ {
+ layout_type (c_union_type);
+ /* Set the back-end type mode now that all fields have had their size
+ set. */
+ compute_record_mode (c_union_type);
+ }
+
+ /* Finish debugging output for this type. */
+ build_stub_type_decl (c_union_type, NULL_TREE /* context */);
+ rest_of_type_compilation (c_union_type, TYPE_FILE_SCOPE_P (c_union_type));
+ rest_of_decl_compilation (TYPE_NAME (c_union_type), 1 /* file scope p */, 0);
+
+ /* Now the type with the overhead. */
+ TYPE_NAME (union_type) = get_identifier ("union%");
+ tree overhead_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+ get_identifier ("overhead%"), sizetype);
+ tree value_field = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+ get_identifier ("value%"), c_union_type);
+ DECL_FIELD_CONTEXT (overhead_field) = union_type;
+ DECL_FIELD_CONTEXT (value_field) = union_type;
+ DECL_CHAIN (value_field) = NULL_TREE;
+ DECL_CHAIN (overhead_field) = value_field;
+ TYPE_FIELDS (union_type) = overhead_field;
+
+ if (c_union_type_complete)
+ {
+ layout_type (union_type);
+ /* Set the back-end type mode now that all fields have had their size
+ set. */
+ compute_record_mode (union_type);
+ }
+ else
+ {
+ tree forward_refs = tree_cons (NULL_TREE, value_field,
+ TYPE_FORWARD_REFERENCES (union_type));
+ TYPE_FORWARD_REFERENCES (union_type) = forward_refs;
+ }
+
+ SET_TYPE_STRUCTURAL_EQUALITY (union_type);
+ A68_UNION_TYPE_P (union_type) = 1;
+ return union_type;
+}
+
+/* Return the type for an array descriptor triplet. */
+
+tree
+a68_triplet_type (void)
+{
+ static tree triplet_type = NULL_TREE;
+ if (triplet_type == NULL_TREE)
+ {
+ triplet_type = make_struct_type (NULL_TREE, "triplet%", 3,
+ get_identifier ("lb%"),
+ ssizetype,
+ get_identifier ("ub%"),
+ ssizetype,
+ get_identifier ("stride%"),
+ sizetype);
+ }
+
+ return triplet_type;
+}
+
+/* Return the lower bound field in an array descriptor triplet. */
+
+tree
+a68_triplet_type_lower_bound (tree triplet)
+{
+ tree lb_field = TYPE_FIELDS (triplet);
+ return lb_field;
+}
+
+/* Lower a row mode to a GENERIC tree.
+
+ descriptor%
+ triplets% Value of ARRAY_TYPE with an entry per multiple dimension.
+ {
+ li% Lower bound of dimension.
+ ui% Upper bound of dimension.
+ di% Stride of dimension in bytes.
+ }
+ elements% Pointer to the elements.
+ elements_size% Size of elements% in bytes.
+*/
+
+static tree
+lower_row_mode (MOID_T *m)
+{
+ int num_dimensions = DIM (m);
+ tree triplet_type = a68_triplet_type ();
+ tree triplets_type = build_array_type (triplet_type,
+ build_index_type (size_int
(num_dimensions - 1)));
+ tree element_type = a68_lower_mode (SUB (m));
+ tree row_type = make_struct_type (NULL_TREE, "row%", 3,
+ get_identifier ("triplets%"),
+ triplets_type,
+ get_identifier ("elements%"),
+ build_pointer_type (element_type),
+ get_identifier ("elements_size%"),
+ sizetype);
+ layout_type (row_type);
+ A68_ROW_TYPE_P (row_type) = 1;
+ return row_type;
+}
+
+/* Given a row type, return the type of the pointer to its elements. */
+
+tree
+a68_row_elements_pointer_type (tree type)
+{
+ gcc_assert (A68_ROW_TYPE_P (type));
+ /* elements% is the second field. */
+ return TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (type)));
+}
+
+/* Given a row type, return the type of its elements. */
+
+tree
+a68_row_elements_type (tree type)
+{
+ return TREE_TYPE (a68_row_elements_pointer_type (type));
+}
+
+/* Lower a ROWS mode to a GENERIC tree.
+
+ dim% Number of dimensions.
+ triplets% Pointer to triplets.
+
+ Values of this mode are passed to the operators UPB, LWB and ELEMS, which
+ need only descriptor information. There is no need to store any multiple
+ elements. */
+
+static tree
+lower_rows_mode (MOID_T *m ATTRIBUTE_UNUSED)
+{
+ static tree rows_type = NULL_TREE;
+
+ if (rows_type == NULL_TREE)
+ {
+ rows_type = make_struct_type (NULL_TREE, "rows%", 2,
+ get_identifier ("dim%"),
+ sizetype,
+ get_identifier ("triplets%"),
+ build_pointer_type (a68_triplet_type ()));
+ A68_ROWS_TYPE_P (rows_type) = 1;
+ }
+ return rows_type;
+}
+
+/* Lower modes in a series. This is used as the mode of the mode yielded by an
+ enclosed clause that yields a series of united rows, for M_ROWS. */
+
+static tree
+lower_series (MOID_T *m)
+{
+ for (PACK_T *p = PACK (m); p != NO_PACK; FORWARD (p))
+ {
+ if (IS (MOID (p), SERIES_MODE) || IS (MOID (p), STOWED_MODE))
+ lower_series (MOID (p));
+ else
+ (void) a68_lower_mode (MOID (p));
+ }
+
+ return lower_rows_mode (NO_MOID);
+}
+
+/* Lower a mode to a GENERIC tree. */
+
+static tree
+a68_lower_mode (MOID_T *m)
+{
+ tree type = NULL_TREE;
+
+ /* If the given mode has already been lowered, return the corresponding
+ tree. */
+ if (CTYPE (m) != NULL)
+ return CTYPE (m);
+
+ if (EQUIVALENT (m) != NO_MOID && EQUIVALENT (m) != m)
+ /* This covers INDICANTs and standard MOIDS having an equivalent mode. */
+ type = a68_lower_mode (EQUIVALENT (m));
+ else if (m == M_VOID)
+ type = a68_void_type;
+ else if (m == M_HIP)
+ type = lower_hip_mode (m);
+ else if (IS (m, STANDARD))
+ type = lower_standard_mode (m);
+ else if (IS_REF (m))
+ type = lower_ref_mode (m);
+ else if (IS_FLEX (m))
+ type = lower_flex_mode (m);
+ else if (IS (m, PROC_SYMBOL))
+ type = lower_proc_mode (m);
+ else if (IS_STRUCT (m))
+ type = lower_struct_mode (m);
+ else if (IS_ROW (m))
+ type = lower_row_mode (m);
+ else if (IS_UNION (m))
+ type = lower_union_mode (m);
+ else if (m == M_SIMPLOUT || m == M_SIMPLIN)
+ type = a68_void_type;
+ else if (IS (m, ROWS_SYMBOL))
+ /* ROWS is a mode that means "any row mode". */
+ type = lower_rows_mode (m);
+ else if (m == M_VACUUM)
+ /* This is a mode that should not survive the parser. */
+ type = a68_void_type;
+ else if (IS (m, SERIES_MODE) || IS (m, STOWED_MODE))
+ {
+ /* When dealing with operators the parser creates some modes that leak
+ SERIES and STOWED "proto-modes" in them, such as for example:
+
+ UNION ((INT, INT), INT, PROC [] CHAR)
+
+ These are not really real Algol 68 modes and are useless by
+ themselves, so when we find them, we traverse them (they ultimately
+ contain valid modes that may show up in other contexts and that
+ require being lowered) and just report them as VOID. */
+ type = lower_series (m);
+ }
+ else
+ {
+ fatal_error (NODE (m) ? a68_get_node_location (NODE (m)) :
UNKNOWN_LOCATION,
+ "Cannot lower mode %s",
+ a68_moid_to_string (m, MOID_ERROR_WIDTH, NODE (m)));
+ }
+
+ /* Associate the created tree node with the mode, and vice-versa. */
+ gcc_assert (type != NULL_TREE);
+ TYPE_LANG_SPECIFIC (type) = a68_build_lang_type (m);
+ A68_TYPE_HAS_ROWS_P (type) = HAS_ROWS (m);
+ if (CTYPE (m) == NULL_TREE)
+ CTYPE (m) = type;
+ // printf ("DONE LOWERING %s\n", a68_moid_to_string (m, MOID_ERROR_WIDTH,
NODE (m)));
+ return type;
+}
+
+/* Lower MOIDs to GENERIC trees. */
+
+void
+a68_lower_moids (MOID_T *mode)
+{
+ /* First pass: all modes but refs. */
+ for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
+ (void) a68_lower_mode (m);
+
+ /* Try to layout all incomplete types. This is a two-passes process. */
+
+ for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
+ {
+ if (IS_STRUCT (m))
+ {
+ tree struct_type = CTYPE (m);
+ finish_incomplete_fields (struct_type);
+ }
+ else if (IS_UNION (m))
+ {
+ tree union_type = CTYPE (m);
+ tree c_union_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (union_type)));
+ finish_incomplete_fields (c_union_type);
+ finish_incomplete_fields (union_type);
+ }
+ }
+
+ for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
+ {
+ if (!COMPLETE_TYPE_P (CTYPE (m)))
+ {
+ if (IS_STRUCT (m))
+ {
+ tree struct_type = CTYPE (m);
+ layout_type (struct_type);
+ compute_record_mode (struct_type);
+ }
+ else if (IS_UNION (m))
+ {
+ tree union_type = CTYPE (m);
+ tree c_union_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS
(union_type)));
+
+ if (!COMPLETE_TYPE_P (c_union_type))
+ {
+ layout_type (c_union_type);
+ compute_record_mode (c_union_type);
+ }
+
+ layout_type (union_type);
+ compute_record_mode (union_type);
+ }
+ else
+ layout_type (CTYPE (m));
+ }
+ }
+
+ /* Sanity check. */
+ for (MOID_T *m = mode; m != NO_MOID; FORWARD (m))
+ {
+ gcc_assert (COMPLETE_TYPE_P (CTYPE (m)));
+ if (IS_UNION (m))
+ {
+ tree union_type = CTYPE (m);
+ tree c_union_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (union_type)));
+ gcc_assert (COMPLETE_TYPE_P (c_union_type));
+ }
+ }
+}
--
2.30.2