This commit implements several improvements:
1. The optimization for avoiding indirect calls while using
declarations like:
proc(string)int puts = nest C "_libga68_posixputs";
has been completed.
2. Algol 68 procedures getting strings as arguments can now
wrap corresponding C functions. Note this does not include
procedures yielding strings as for now.
3. Wrappers are now built for all formal holes having proc mode. This
allows for a more robust implementation.
Signed-off-by: Jose E. Marchesi <[email protected]>
gcc/algol68/ChangeLog
* Make-lang.in (ALGOL68_OBJS): Add algol68/a68-low-holes.o.
* a68.h: Update prototypes.
* a68-types.h (struct TAG_T): New field nest_proc.
(NEST_PROC): Define.
* a68-parser.cc (a68_new_tag): Initialize NEST_PROC.
* a68-parser-extract.cc (extract_identities): Use NEST_PROC
instead of IN_PROC for taxes for defining-identifiers in identity
declarations of proc modes with formal holes as actual parameters.
* a68-moids-misc.cc (a68_is_c_mode): Modified to allow strings as
direct parameters.
* a68-low.cc (a68_make_proc_formal_hole_decl): Remove.
* a68-low-units.cc (a68_lower_identifier): Improve commentary.
(a68_lower_formal_hole): Factorize.
* a68-low-holes.cc: New file.
* a68-low-decls.cc (a68_lower_identity_declaration): Optimize
identity declarations of proc mode with formal holes as actual
parameters.
* a68-exports.cc (a68_add_identifier_to_moif): Honor NEST_PROC.
* ga68.texi (Communicating with C): Strings can now be passed as
parameters in formal holes.
gcc/testsuite/ChangeLog
* algol68/compile/error-nest-4.a68: Strings can now be passed as
arguments in formal holes.
---
gcc/algol68/Make-lang.in | 1 +
gcc/algol68/a68-exports.cc | 2 +-
gcc/algol68/a68-low-decls.cc | 75 +++++---
gcc/algol68/a68-low-holes.cc | 176 ++++++++++++++++++
gcc/algol68/a68-low-units.cc | 84 +++++++--
gcc/algol68/a68-low.cc | 31 +--
gcc/algol68/a68-moids-misc.cc | 13 +-
gcc/algol68/a68-parser-extract.cc | 2 +-
gcc/algol68/a68-parser.cc | 1 +
gcc/algol68/a68-types.h | 8 +-
gcc/algol68/a68.h | 8 +-
gcc/algol68/ga68.texi | 11 ++
.../algol68/compile/error-nest-4.a68 | 2 +-
13 files changed, 329 insertions(+), 85 deletions(-)
create mode 100644 gcc/algol68/a68-low-holes.cc
diff --git a/gcc/algol68/Make-lang.in b/gcc/algol68/Make-lang.in
index 027ff0c3baf..54b5381cb81 100644
--- a/gcc/algol68/Make-lang.in
+++ b/gcc/algol68/Make-lang.in
@@ -109,6 +109,7 @@ ALGOL68_OBJS = algol68/a68-lang.o \
algol68/a68-low-runtime.o \
algol68/a68-low-unions.o \
algol68/a68-low-units.o \
+ algol68/a68-low-holes.o \
$(END)
ALGOL68_ALL_OBJS = $(ALGOL68_OBJS)
diff --git a/gcc/algol68/a68-exports.cc b/gcc/algol68/a68-exports.cc
index 64f31da4016..4ab6ce53d1a 100644
--- a/gcc/algol68/a68-exports.cc
+++ b/gcc/algol68/a68-exports.cc
@@ -91,7 +91,7 @@ a68_add_identifier_to_moif (MOIF_T *moif, TAG_T *tag)
EXTRACT_MODE (e) = MOID (tag);
EXTRACT_PRIO (e) = 0;
EXTRACT_VARIABLE (e) = VARIABLE (tag);
- EXTRACT_IN_PROC (e) = IN_PROC (tag);
+ EXTRACT_IN_PROC (e) = IN_PROC (tag) || NEST_PROC (tag);
if (! IDENTIFIERS (moif)->contains (e))
{
diff --git a/gcc/algol68/a68-low-decls.cc b/gcc/algol68/a68-low-decls.cc
index 0b99f9352ad..56edacf5092 100644
--- a/gcc/algol68/a68-low-decls.cc
+++ b/gcc/algol68/a68-low-decls.cc
@@ -351,38 +351,55 @@ a68_lower_identity_declaration (NODE_T *p, LOW_CTX_T ctx)
NODE_T *unit = NEXT (NEXT (defining_identifier));
- /* If not done already by an applied identifier in lower_identifier, create a
- declaration for the defined entity and chain it in the current block. The
- declaration has an initial value of SKIP. */
- tree id_decl = TAX_TREE_DECL (TAX (defining_identifier));
- if (id_decl == NULL_TREE)
+ tree expr = NULL_TREE;
+ if (NEST_PROC (TAX (defining_identifier)))
{
- id_decl = a68_make_identity_declaration_decl (defining_identifier,
- ctx.module_definition_name);
- TAX_TREE_DECL (TAX (defining_identifier)) = id_decl;
- }
+ /* NEST_PROC tells us that the identity declaration is of the form:
- /* If the identity declaration is in a public range then add the declaration
- to the publicized declarations list. Otherwise chain the declaration in
- the proper block and bind it. */
- if (PUBLIC_RANGE (TABLE (TAX (defining_identifier))))
- vec_safe_push (A68_MODULE_DEFINITION_DECLS, id_decl);
- else
- a68_add_decl (id_decl);
+ PROCMODE defining_identifier = FORMAL_HOLE
- /* Prepare the DECL_EXPR. */
- a68_add_decl_expr (fold_build1_loc (a68_get_node_location (p),
- DECL_EXPR,
- TREE_TYPE (id_decl),
- id_decl));
-
- unit_tree = a68_lower_tree (unit, ctx);
- unit_tree = a68_consolidate_ref (MOID (unit), unit_tree);
- tree expr = a68_low_ascription (MOID (defining_identifier),
- id_decl, unit_tree);
+ Which in effect is very like a procedure declaration. */
+ gcc_assert (IS (SUB (unit), FORMAL_HOLE));
+ ctx.proc_decl_identifier = defining_identifier;
+ ctx.proc_decl_operator = false;
+ expr = a68_lower_tree (unit, ctx);
+ }
+ else
+ {
+ /* For regular identity declarations, create a declaration for the
+ defined entity and chain it in the current block. The declaration has
+ an initial value of SKIP. */
+ tree id_decl = TAX_TREE_DECL (TAX (defining_identifier));
+ if (id_decl == NULL_TREE)
+ {
+ id_decl = a68_make_identity_declaration_decl (defining_identifier,
+
ctx.module_definition_name);
+ TAX_TREE_DECL (TAX (defining_identifier)) = id_decl;
+ }
- /* If the ascribed value is constant, mark the declaration as constant. */
- TREE_CONSTANT (id_decl) = TREE_CONSTANT (unit_tree);
+ /* Prepare the DECL_EXPR. */
+ a68_add_decl_expr (fold_build1_loc (a68_get_node_location (p),
+ DECL_EXPR,
+ TREE_TYPE (id_decl),
+ id_decl));
+
+ unit_tree = a68_lower_tree (unit, ctx);
+ unit_tree = a68_consolidate_ref (MOID (unit), unit_tree);
+ expr = a68_low_ascription (MOID (defining_identifier),
+ id_decl, unit_tree);
+
+ /* If the ascribed value is constant, mark the declaration as
+ constant. */
+ TREE_CONSTANT (id_decl) = TREE_CONSTANT (unit_tree);
+
+ /* If the identity declaration is in a public range then add the
+ declaration to the module's declarations list. Otherwise chain the
+ declaration in the proper block and bind it. */
+ if (PUBLIC_RANGE (TABLE (TAX (defining_identifier))))
+ vec_safe_push (A68_MODULE_DEFINITION_DECLS, id_decl);
+ else
+ a68_add_decl (id_decl);
+ }
/* Tail in a compound expression with sub declarations, if any. */
if (sub_expr != NULL_TREE)
@@ -390,7 +407,7 @@ a68_lower_identity_declaration (NODE_T *p, LOW_CTX_T ctx)
if (expr != NULL_TREE)
expr = fold_build2_loc (a68_get_node_location (p),
COMPOUND_EXPR,
- TREE_TYPE (id_decl),
+ TREE_TYPE (expr),
sub_expr,
expr);
else
diff --git a/gcc/algol68/a68-low-holes.cc b/gcc/algol68/a68-low-holes.cc
new file mode 100644
index 00000000000..2a6a02a9020
--- /dev/null
+++ b/gcc/algol68/a68-low-holes.cc
@@ -0,0 +1,176 @@
+/* Lowering routines for formal holes.
+ Copyright (C) 2026 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 "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "predict.h"
+#include "stor-layout.h"
+#include "tree-iterator.h"
+#include "stringpool.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "dumpfile.h"
+#include "convert.h"
+
+#include "a68.h"
+
+/* Get the symbol associated with the formal hole P. *ADDRP is set to `true' if
+ the string denotation in the formal hole starts with `&'. */
+
+static const char *
+get_hole_symbol (NODE_T *p, bool *addrp)
+{
+ NODE_T *str = NEXT_SUB (p);
+ if (IS (str, LANGUAGE_INDICANT))
+ FORWARD (str);
+ gcc_assert (IS (str, TERTIARY));
+ while (str != NO_NODE && !IS (str, ROW_CHAR_DENOTATION))
+ str = SUB (str);
+ gcc_assert (IS (str, ROW_CHAR_DENOTATION));
+
+ const char *cstr = NSYMBOL (str);
+ if (strlen (cstr) > 0 && cstr[0] == '&' && addrp != NULL)
+ {
+ *addrp = true;
+ cstr = cstr + 1;
+ }
+
+ return a68_string_process_breaks (p, cstr);
+}
+
+/* Build and return a var decl providing access to the formal hole P. */
+
+tree
+a68_wrap_formal_var_hole (NODE_T *p)
+{
+ gcc_assert (!IS (MOID (p), PROC_SYMBOL));
+ const char *symbol = get_hole_symbol (p, NULL /* addrp */);
+ return a68_make_formal_hole_decl (p, symbol);
+}
+
+/* Build the body for a wrapper to the formal hole in P, which is of a proc
+ mode. The body is installed in the function_decl WRAPPER. */
+
+void
+a68_wrap_formal_proc_hole (NODE_T *p, tree wrapper)
+{
+ gcc_assert (IS (MOID (p), PROC_SYMBOL));
+
+ bool addrp;
+ const char *symbol = get_hole_symbol (p, &addrp);
+ gcc_assert (addrp == false);
+
+ /* Create a wrapper function. */
+
+ MOID_T *m = MOID (p);
+
+ /* Determine how many arguments we need for the wrapped function. */
+ int wrapped_nargs = 0;
+ for (PACK_T *z = PACK (m); z != NO_PACK; FORWARD (z))
+ {
+ if (MOID(z) == M_STRING)
+ wrapped_nargs += 3;
+ else
+ wrapped_nargs += 1;
+ }
+
+ /* Now build the type of the wrapped function. */
+
+ tree *wrapped_args_types = XALLOCAVEC (tree, wrapped_nargs);
+ int nwrappedarg = 0;
+ for (PACK_T *z = PACK (m); z != NO_PACK; FORWARD (z))
+ {
+ if (MOID (z) == M_STRING)
+ {
+ wrapped_args_types[nwrappedarg++] = build_pointer_type
(a68_char_type);
+ wrapped_args_types[nwrappedarg++] = size_type_node;
+ wrapped_args_types[nwrappedarg++] = size_type_node;
+ }
+ else
+ {
+ wrapped_args_types[nwrappedarg++] = CTYPE (MOID (z));
+ }
+ }
+
+ tree wrapper_ret_type = TREE_TYPE (TREE_TYPE (wrapper));
+ tree wrapped_type = build_function_type_array (wrapper_ret_type,
+ wrapped_nargs,
+ wrapped_args_types);
+
+ /* And a decl for the wrapped function. */
+ tree wrapped = build_decl (UNKNOWN_LOCATION,
+ FUNCTION_DECL,
+ get_identifier (symbol),
+ wrapped_type);
+ DECL_EXTERNAL (wrapped) = 1;
+ TREE_PUBLIC (wrapped) = 1;
+ DECL_ARTIFICIAL (wrapped) = 1;
+ DECL_VISIBILITY (wrapped) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (wrapped) = 1;
+
+ announce_function (wrapper);
+
+ vec<tree, va_gc> *wrapped_args;
+ vec_alloc (wrapped_args, wrapped_nargs);
+ for (PACK_T *z = PACK (m); z != NO_PACK; FORWARD (z))
+ {
+ if (MOID (z) == M_STRING)
+ {
+ tree str = a68_low_func_param (wrapper, "str", CTYPE (M_STRING));
+ DECL_ARGUMENTS (wrapper) = chainon (str, DECL_ARGUMENTS (wrapper));
+
+ tree s = a68_multiple_elements (str);
+ tree len = a68_multiple_num_elems (str);
+ tree stride = a68_multiple_stride (str, size_zero_node /* dim */);
+
+ wrapped_args->quick_push (s);
+ wrapped_args->quick_push (len);
+ wrapped_args->quick_push (stride);
+ }
+ else
+ {
+ tree a = a68_low_func_param (wrapper, "param", CTYPE (MOID (z)));
+ DECL_ARGUMENTS (wrapper) = chainon (a, DECL_ARGUMENTS (wrapper));
+ wrapped_args->quick_push (a);
+ }
+ }
+ DECL_ARGUMENTS (wrapper) = nreverse (DECL_ARGUMENTS (wrapper));
+
+ a68_push_function_range (wrapper, wrapper_ret_type, true /* top_level */);
+
+ /* We need a pointer to a function type. */
+ if (!POINTER_TYPE_P (TREE_TYPE (wrapped)))
+ wrapped = fold_build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (wrapped)),
+ wrapped);
+
+ tree body = build_call_vec (TREE_TYPE (wrapped_type), wrapped, wrapped_args);
+ a68_pop_function_range (body);
+}
diff --git a/gcc/algol68/a68-low-units.cc b/gcc/algol68/a68-low-units.cc
index 4002a4b608a..5aa0c97dad3 100644
--- a/gcc/algol68/a68-low-units.cc
+++ b/gcc/algol68/a68-low-units.cc
@@ -79,6 +79,7 @@ a68_lower_identifier (NODE_T *p, LOW_CTX_T ctx)
if (IS (MOID (p), PROC_SYMBOL))
{
bool external = (MOIF (TAX (p)) != NO_MOIF);
+
const char *extern_symbol = EXTERN_SYMBOL (TAX (p));
if (VARIABLE (TAX (p)))
{
@@ -90,7 +91,7 @@ a68_lower_identifier (NODE_T *p, LOW_CTX_T ctx)
id_decl
= a68_make_variable_declaration_decl (p,
ctx.module_definition_name);
}
- else if (IN_PROC (TAX (p)))
+ else if (IN_PROC (TAX (p)) || NEST_PROC (TAX (p)))
{
if (external)
id_decl
@@ -144,8 +145,9 @@ a68_lower_identifier (NODE_T *p, LOW_CTX_T ctx)
TAX_TREE_DECL (TAX (p)) = id_decl;
}
- /* If the identifier refers to a FUNCTION_DECL, this means the
declaration
- was made by a procecure-identity-dclaration. The applied identifier in
+ /* If the identifier refers to a FUNCTION_DECL, this means the
+ declaration was made by a procecure-identity-dclaration or a
+ proc-identity-declaration of a formal hole. The applied identifier in
that case refers to the address of the corresponding function. */
if (TREE_CODE (id_decl) == FUNCTION_DECL)
return fold_build1 (ADDR_EXPR,
@@ -1247,22 +1249,68 @@ a68_lower_routine_text (NODE_T *p, LOW_CTX_T ctx)
tree
a68_lower_formal_hole (NODE_T *p, LOW_CTX_T ctx ATTRIBUTE_UNUSED)
{
- NODE_T *str = NEXT_SUB (p);
- if (IS (str, LANGUAGE_INDICANT))
- FORWARD (str);
- gcc_assert (IS (str, TERTIARY));
- while (str != NO_NODE && !IS (str, ROW_CHAR_DENOTATION))
- str = SUB (str);
- gcc_assert (IS (str, ROW_CHAR_DENOTATION));
-
- char *symbol = a68_string_process_breaks (p, NSYMBOL (str));
-
- tree decl;
- if (IS (MOID (p), PROC_SYMBOL))
- decl = a68_make_proc_formal_hole_decl (p, symbol);
+ NODE_T *defining_identifier = ctx.proc_decl_identifier;
+ bool defining_operator = ctx.proc_decl_operator;
+
+ if (defining_identifier != NO_NODE)
+ {
+ /* The formal-hole is part of an identity declaration and yields a proc
+ mode. */
+ gcc_assert (IS (MOID (p), PROC_SYMBOL));
+
+ tree func_decl = TAX_TREE_DECL (TAX (defining_identifier));
+ if (func_decl == NULL_TREE)
+ {
+ /* Note that for PROC modes (which are non-REF) the function below
+ always returns a func_decl, never an address. */
+ func_decl
+ = a68_make_proc_identity_declaration_decl (defining_identifier,
+
ctx.module_definition_name,
+ defining_operator /*
indicant */);
+ TAX_TREE_DECL (TAX (defining_identifier)) = func_decl;
+ }
+
+ /* Create the body for the wrapper from the formal hole. */
+ a68_wrap_formal_proc_hole (p, func_decl);
+
+ /* If the identity-declaration is in a public range then add the
+ declaration to the module's declarations list. Otherwise chain the
+ declaration in the proper block and bind it. */
+ if (PUBLIC_RANGE (TABLE (TAX (defining_identifier))))
+ vec_safe_push (A68_MODULE_DEFINITION_DECLS, func_decl);
+ else
+ a68_add_decl (func_decl);
+
+ a68_add_decl_expr (fold_build1_loc (a68_get_node_location (p),
+ DECL_EXPR,
+ TREE_TYPE (func_decl),
+ func_decl));
+ return func_decl;
+ }
else
- decl = a68_make_formal_hole_decl (p, symbol);
- return decl;
+ {
+ /* The formal-hole is free standing. */
+ tree decl;
+ if (IS (MOID (p), PROC_SYMBOL))
+ {
+ decl = a68_make_anonymous_routine_decl (MOID (p));
+ a68_add_decl (decl);
+ a68_wrap_formal_proc_hole (p, decl);
+
+ /* XXX necessary */
+ a68_add_decl_expr (fold_build1_loc (a68_get_node_location (p),
+ DECL_EXPR,
+ TREE_TYPE (decl),
+ decl));
+ decl = fold_build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (decl)),
+ decl);
+ }
+ else
+ decl = a68_wrap_formal_var_hole (p);
+
+ return decl;
+ }
}
/* Lower an unit.
diff --git a/gcc/algol68/a68-low.cc b/gcc/algol68/a68-low.cc
index 1f341aaa977..dcc974ad67d 100644
--- a/gcc/algol68/a68-low.cc
+++ b/gcc/algol68/a68-low.cc
@@ -660,33 +660,6 @@ a68_make_formal_hole_decl (NODE_T *p, const char
*extern_symbol)
return decl;
}
-/* Make an extern declaration for a formal hole that is a function. */
-
-tree
-a68_make_proc_formal_hole_decl (NODE_T *p, const char *extern_symbol)
-{
- /* The CTYPE of MODE is a pointer to a function. We need the pointed
- function type for the FUNCTION_DECL. */
- tree type = TREE_TYPE (CTYPE (MOID (p)));
-
- gcc_assert (strlen (extern_symbol) > 0);
- const char *sym = (extern_symbol[0] == '&'
- ? extern_symbol + 1
- : extern_symbol);
-
- tree decl = build_decl (a68_get_node_location (p),
- FUNCTION_DECL,
- get_identifier (sym),
- type);
- DECL_EXTERNAL (decl) = 1;
- TREE_PUBLIC (decl) = 1;
- DECL_INITIAL (decl) = a68_get_skip_tree (MOID (p));
-
- if (extern_symbol[0] == '&')
- decl = fold_build1 (ADDR_EXPR, type, decl);
- return decl;
-}
-
/* Do a checked indirection.
P is a tree node used for its location information.
@@ -1448,7 +1421,9 @@ lower_module_declaration (NODE_T *p, LOW_CTX_T ctx)
for (tree d : A68_MODULE_DEFINITION_DECLS)
{
if (TREE_CODE (d) == FUNCTION_DECL)
- cgraph_node::finalize_function (d, true);
+ {
+ cgraph_node::finalize_function (d, true);
+ }
else
{
rest_of_decl_compilation (d, 1, 0);
diff --git a/gcc/algol68/a68-moids-misc.cc b/gcc/algol68/a68-moids-misc.cc
index a8817926b88..585a4aa691d 100644
--- a/gcc/algol68/a68-moids-misc.cc
+++ b/gcc/algol68/a68-moids-misc.cc
@@ -1193,7 +1193,7 @@ a68_determine_unique_mode (SOID_T *z, int deflex)
metaproduction rule 561B in ga68.vw. */
bool
-a68_is_c_mode (MOID_T *m)
+a68_is_c_mode (MOID_T *m, int level)
{
if (m == M_VOID || m == M_BOOL || m == M_CHAR)
return true;
@@ -1204,14 +1204,19 @@ a68_is_c_mode (MOID_T *m)
else if (IS_REAL (m))
return true;
else if (IS_REF (m))
- return a68_is_c_mode (SUB (m));
+ return a68_is_c_mode (SUB (m), level + 1);
else if (IS (m, PROC_SYMBOL))
{
bool yielded_mode_valid = a68_is_c_mode (SUB (m));
bool params_valid = true;
for (PACK_T *z = PACK (m); z != NO_PACK; FORWARD (z))
- params_valid &= a68_is_c_mode (MOID (z));
+ {
+ if (level == 0 && MOID (z) == M_STRING)
+ ;
+ else
+ params_valid &= a68_is_c_mode (MOID (z), level + 1);
+ }
return yielded_mode_valid && params_valid;
}
@@ -1220,7 +1225,7 @@ a68_is_c_mode (MOID_T *m)
bool fields_valid = true;
for (PACK_T *z = PACK (m); z != NO_PACK; FORWARD (z))
- fields_valid &= a68_is_c_mode (MOID (z));
+ fields_valid &= a68_is_c_mode (MOID (z), level + 1);
return fields_valid;
}
diff --git a/gcc/algol68/a68-parser-extract.cc
b/gcc/algol68/a68-parser-extract.cc
index 34199595856..611ef12d2eb 100644
--- a/gcc/algol68/a68-parser-extract.cc
+++ b/gcc/algol68/a68-parser-extract.cc
@@ -775,7 +775,7 @@ extract_identities (NODE_T *p)
{
NODE_T *actual_param = NEXT (NEXT (q));
if (actual_param != NO_NODE && IS (actual_param,
FORMAL_NEST_SYMBOL))
- IN_PROC (tag) = true;
+ NEST_PROC (tag) = true;
}
FORWARD (q);
ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
diff --git a/gcc/algol68/a68-parser.cc b/gcc/algol68/a68-parser.cc
index 939dbdde2ec..885b5f524d9 100644
--- a/gcc/algol68/a68-parser.cc
+++ b/gcc/algol68/a68-parser.cc
@@ -778,6 +778,7 @@ a68_new_tag (void)
PRIO (z) = 0;
USE (z) = false;
IN_PROC (z) = false;
+ NEST_PROC (z) = false;
HEAP (z) = false;
YOUNGEST_ENVIRON (z) = PRIMAL_SCOPE;
LOC_ASSIGNED (z) = false;
diff --git a/gcc/algol68/a68-types.h b/gcc/algol68/a68-types.h
index f18d3501799..eaf8e1900f6 100644
--- a/gcc/algol68/a68-types.h
+++ b/gcc/algol68/a68-types.h
@@ -596,6 +596,11 @@ struct GTY(()) TABLE_T
are optimized in a similar way than variable declarations in order to avoid
indirect addressing.
+ NEST_PROC is set when the defining identifier has been set in an
+ identity-declaration of a proc mode with a formal hole as actual parameter.
+ These declarations are optimized in a similar way than variable declarations
+ in order to avoid indirect addressing.
+
YOUNGEST_ENVIRON is used when NODE is either a ROUTINE_TEXT or a
FORMAT_TEXT, and contains the youngest (higher) lexical level of any object
directly declared in the routine or format body. This is filled in and used
@@ -620,7 +625,7 @@ struct GTY((chain_next ("%h.next"))) TAG_T
MOID_T *type;
NODE_T *node, *unit;
const char *value;
- bool scope_assigned, use, in_proc, loc_assigned, portable, variable;
+ bool scope_assigned, use, in_proc, nest_proc, loc_assigned, portable,
variable;
bool ascribed_routine_text, is_recursive, publicized;
int priority, heap, scope, youngest_environ, number;
STATUS_MASK_T status;
@@ -1013,6 +1018,7 @@ struct GTY(()) A68_T
#define MULTIPLE_MODE(p) ((p)->multiple_mode)
#define NAME(p) ((p)->name)
#define NEST(p) ((p)->nest)
+#define NEST_PROC(p) ((p)->nest_proc)
#define NEXT(p) ((p)->next)
#define NEXT_NEXT(p) (NEXT (NEXT (p)))
#define NEXT_NEXT_NEXT(p) (NEXT (NEXT_NEXT (p)))
diff --git a/gcc/algol68/a68.h b/gcc/algol68/a68.h
index 9dcb14600a2..2492aea6e2a 100644
--- a/gcc/algol68/a68.h
+++ b/gcc/algol68/a68.h
@@ -476,7 +476,7 @@ void a68_make_soid (SOID_T *s, int sort, MOID_T *type, int
attribute);
void a68_make_strong (NODE_T *n, MOID_T *p, MOID_T *q);
void a68_make_uniting_coercion (NODE_T *n, MOID_T *q);
void a68_make_void (NODE_T *p, MOID_T *q);
-bool a68_is_c_mode (MOID_T *m);
+bool a68_is_c_mode (MOID_T *m, int level = 0);
#define A68_DEPREF true
#define A68_NO_DEPREF false
@@ -815,7 +815,6 @@ tree a68_make_proc_identity_declaration_decl (NODE_T
*identifier, const char *mo
bool indicant = false, bool
external = false,
const char *extern_symbol = NULL);
tree a68_make_formal_hole_decl (NODE_T *p, const char *extern_symbol);
-tree a68_make_proc_formal_hole_decl (NODE_T *p, const char *extern_symbol);
tree a68_make_anonymous_routine_decl (MOID_T *mode);
tree a68_get_skip_tree (MOID_T *m);
tree a68_get_empty (void);
@@ -857,6 +856,11 @@ tree a68_union_value (MOID_T *mode, tree exp, MOID_T
*exp_mode);
tree a68_union_translate_overhead (MOID_T *from, tree from_overhead, MOID_T
*to);
bool a68_union_contains_mode (MOID_T *p, MOID_T *q);
+/* a68-low-holes.cc */
+
+tree a68_wrap_formal_var_hole (NODE_T *p);
+void a68_wrap_formal_proc_hole (NODE_T *p, tree fndecl);
+
/* a68-low-units.cc */
tree a68_lower_identifier (NODE_T *p, LOW_CTX_T ctx);
diff --git a/gcc/algol68/ga68.texi b/gcc/algol68/ga68.texi
index b0945bf8535..bbf2387b61e 100644
--- a/gcc/algol68/ga68.texi
+++ b/gcc/algol68/ga68.texi
@@ -1305,6 +1305,17 @@ As C @code{unsigned long long} or as C @code{unsigned
long} or as C @code{unsign
As C @code{float}
@item @code{@B{long} @B{real}}
As C @code{double}
+@item @code{string} but only as formal parameters of procedures
+Each Algol 68 string formal parameter turns into three parameters in C:
+
+@table @code
+@item uint32_t *s
+A pointer to the UCS-4 characters composing the string.
+@item size_t len
+The length of @code{s} in number of characters.
+@item size_t stride
+The distance in bytes between each character in @code{s}.
+@end table
@item @B{proc} with accepted formal parameter modes and yielded mode
As the corresponding C functions.
@item Structs with fields of accepted modes
diff --git a/gcc/testsuite/algol68/compile/error-nest-4.a68
b/gcc/testsuite/algol68/compile/error-nest-4.a68
index ef40c385766..312b96878a5 100644
--- a/gcc/testsuite/algol68/compile/error-nest-4.a68
+++ b/gcc/testsuite/algol68/compile/error-nest-4.a68
@@ -2,7 +2,7 @@ begin string s =
nest C "lala"; { dg-error "" }
union(int,real) x =
nest C "x"; { dg-error "" }
- proc(string)bool y =
+ proc(union(void,string))bool y =
nest C "y"; { dg-error "" }
skip
end
--
2.39.5