1627f7eb2Smrg /* Implementation of Fortran 2003 Polymorphism.
2*4c3eb207Smrg Copyright (C) 2009-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Paul Richard Thomas <pault@gcc.gnu.org>
4627f7eb2Smrg and Janus Weil <janus@gcc.gnu.org>
5627f7eb2Smrg
6627f7eb2Smrg This file is part of GCC.
7627f7eb2Smrg
8627f7eb2Smrg GCC is free software; you can redistribute it and/or modify it under
9627f7eb2Smrg the terms of the GNU General Public License as published by the Free
10627f7eb2Smrg Software Foundation; either version 3, or (at your option) any later
11627f7eb2Smrg version.
12627f7eb2Smrg
13627f7eb2Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14627f7eb2Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
15627f7eb2Smrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16627f7eb2Smrg for more details.
17627f7eb2Smrg
18627f7eb2Smrg You should have received a copy of the GNU General Public License
19627f7eb2Smrg along with GCC; see the file COPYING3. If not see
20627f7eb2Smrg <http://www.gnu.org/licenses/>. */
21627f7eb2Smrg
22627f7eb2Smrg
23627f7eb2Smrg /* class.c -- This file contains the front end functions needed to service
24627f7eb2Smrg the implementation of Fortran 2003 polymorphism and other
25627f7eb2Smrg object-oriented features. */
26627f7eb2Smrg
27627f7eb2Smrg
28627f7eb2Smrg /* Outline of the internal representation:
29627f7eb2Smrg
30627f7eb2Smrg Each CLASS variable is encapsulated by a class container, which is a
31627f7eb2Smrg structure with two fields:
32627f7eb2Smrg * _data: A pointer to the actual data of the variable. This field has the
33627f7eb2Smrg declared type of the class variable and its attributes
34627f7eb2Smrg (pointer/allocatable/dimension/...).
35627f7eb2Smrg * _vptr: A pointer to the vtable entry (see below) of the dynamic type.
36627f7eb2Smrg
37627f7eb2Smrg Only for unlimited polymorphic classes:
38627f7eb2Smrg * _len: An integer(C_SIZE_T) to store the string length when the unlimited
39627f7eb2Smrg polymorphic pointer is used to point to a char array. The '_len'
40627f7eb2Smrg component will be zero when no character array is stored in
41627f7eb2Smrg '_data'.
42627f7eb2Smrg
43627f7eb2Smrg For each derived type we set up a "vtable" entry, i.e. a structure with the
44627f7eb2Smrg following fields:
45627f7eb2Smrg * _hash: A hash value serving as a unique identifier for this type.
46627f7eb2Smrg * _size: The size in bytes of the derived type.
47627f7eb2Smrg * _extends: A pointer to the vtable entry of the parent derived type.
48627f7eb2Smrg * _def_init: A pointer to a default initialized variable of this type.
49627f7eb2Smrg * _copy: A procedure pointer to a copying procedure.
50627f7eb2Smrg * _final: A procedure pointer to a wrapper function, which frees
51627f7eb2Smrg allocatable components and calls FINAL subroutines.
52627f7eb2Smrg
53627f7eb2Smrg After these follow procedure pointer components for the specific
54627f7eb2Smrg type-bound procedures. */
55627f7eb2Smrg
56627f7eb2Smrg
57627f7eb2Smrg #include "config.h"
58627f7eb2Smrg #include "system.h"
59627f7eb2Smrg #include "coretypes.h"
60627f7eb2Smrg #include "gfortran.h"
61627f7eb2Smrg #include "constructor.h"
62627f7eb2Smrg #include "target-memory.h"
63627f7eb2Smrg
64627f7eb2Smrg /* Inserts a derived type component reference in a data reference chain.
65627f7eb2Smrg TS: base type of the ref chain so far, in which we will pick the component
66627f7eb2Smrg REF: the address of the GFC_REF pointer to update
67627f7eb2Smrg NAME: name of the component to insert
68627f7eb2Smrg Note that component insertion makes sense only if we are at the end of
69627f7eb2Smrg the chain (*REF == NULL) or if we are adding a missing "_data" component
70627f7eb2Smrg to access the actual contents of a class object. */
71627f7eb2Smrg
72627f7eb2Smrg static void
insert_component_ref(gfc_typespec * ts,gfc_ref ** ref,const char * const name)73627f7eb2Smrg insert_component_ref (gfc_typespec *ts, gfc_ref **ref, const char * const name)
74627f7eb2Smrg {
75627f7eb2Smrg gfc_ref *new_ref;
76627f7eb2Smrg int wcnt, ecnt;
77627f7eb2Smrg
78627f7eb2Smrg gcc_assert (ts->type == BT_DERIVED || ts->type == BT_CLASS);
79627f7eb2Smrg
80627f7eb2Smrg gfc_find_component (ts->u.derived, name, true, true, &new_ref);
81627f7eb2Smrg
82627f7eb2Smrg gfc_get_errors (&wcnt, &ecnt);
83627f7eb2Smrg if (ecnt > 0 && !new_ref)
84627f7eb2Smrg return;
85627f7eb2Smrg gcc_assert (new_ref->u.c.component);
86627f7eb2Smrg
87627f7eb2Smrg while (new_ref->next)
88627f7eb2Smrg new_ref = new_ref->next;
89627f7eb2Smrg new_ref->next = *ref;
90627f7eb2Smrg
91627f7eb2Smrg if (new_ref->next)
92627f7eb2Smrg {
93627f7eb2Smrg gfc_ref *next = NULL;
94627f7eb2Smrg
95627f7eb2Smrg /* We need to update the base type in the trailing reference chain to
96627f7eb2Smrg that of the new component. */
97627f7eb2Smrg
98627f7eb2Smrg gcc_assert (strcmp (name, "_data") == 0);
99627f7eb2Smrg
100627f7eb2Smrg if (new_ref->next->type == REF_COMPONENT)
101627f7eb2Smrg next = new_ref->next;
102627f7eb2Smrg else if (new_ref->next->type == REF_ARRAY
103627f7eb2Smrg && new_ref->next->next
104627f7eb2Smrg && new_ref->next->next->type == REF_COMPONENT)
105627f7eb2Smrg next = new_ref->next->next;
106627f7eb2Smrg
107627f7eb2Smrg if (next != NULL)
108627f7eb2Smrg {
109627f7eb2Smrg gcc_assert (new_ref->u.c.component->ts.type == BT_CLASS
110627f7eb2Smrg || new_ref->u.c.component->ts.type == BT_DERIVED);
111627f7eb2Smrg next->u.c.sym = new_ref->u.c.component->ts.u.derived;
112627f7eb2Smrg }
113627f7eb2Smrg }
114627f7eb2Smrg
115627f7eb2Smrg *ref = new_ref;
116627f7eb2Smrg }
117627f7eb2Smrg
118627f7eb2Smrg
119627f7eb2Smrg /* Tells whether we need to add a "_data" reference to access REF subobject
120627f7eb2Smrg from an object of type TS. If FIRST_REF_IN_CHAIN is set, then the base
121627f7eb2Smrg object accessed by REF is a variable; in other words it is a full object,
122627f7eb2Smrg not a subobject. */
123627f7eb2Smrg
124627f7eb2Smrg static bool
class_data_ref_missing(gfc_typespec * ts,gfc_ref * ref,bool first_ref_in_chain)125627f7eb2Smrg class_data_ref_missing (gfc_typespec *ts, gfc_ref *ref, bool first_ref_in_chain)
126627f7eb2Smrg {
127627f7eb2Smrg /* Only class containers may need the "_data" reference. */
128627f7eb2Smrg if (ts->type != BT_CLASS)
129627f7eb2Smrg return false;
130627f7eb2Smrg
131627f7eb2Smrg /* Accessing a class container with an array reference is certainly wrong. */
132627f7eb2Smrg if (ref->type != REF_COMPONENT)
133627f7eb2Smrg return true;
134627f7eb2Smrg
135627f7eb2Smrg /* Accessing the class container's fields is fine. */
136627f7eb2Smrg if (ref->u.c.component->name[0] == '_')
137627f7eb2Smrg return false;
138627f7eb2Smrg
139627f7eb2Smrg /* At this point we have a class container with a non class container's field
140627f7eb2Smrg component reference. We don't want to add the "_data" component if we are
141627f7eb2Smrg at the first reference and the symbol's type is an extended derived type.
142627f7eb2Smrg In that case, conv_parent_component_references will do the right thing so
143627f7eb2Smrg it is not absolutely necessary. Omitting it prevents a regression (see
144627f7eb2Smrg class_41.f03) in the interface mapping mechanism. When evaluating string
145627f7eb2Smrg lengths depending on dummy arguments, we create a fake symbol with a type
146627f7eb2Smrg equal to that of the dummy type. However, because of type extension,
147627f7eb2Smrg the backend type (corresponding to the actual argument) can have a
148627f7eb2Smrg different (extended) type. Adding the "_data" component explicitly, using
149627f7eb2Smrg the base type, confuses the gfc_conv_component_ref code which deals with
150627f7eb2Smrg the extended type. */
151627f7eb2Smrg if (first_ref_in_chain && ts->u.derived->attr.extension)
152627f7eb2Smrg return false;
153627f7eb2Smrg
154627f7eb2Smrg /* We have a class container with a non class container's field component
155627f7eb2Smrg reference that doesn't fall into the above. */
156627f7eb2Smrg return true;
157627f7eb2Smrg }
158627f7eb2Smrg
159627f7eb2Smrg
160627f7eb2Smrg /* Browse through a data reference chain and add the missing "_data" references
161627f7eb2Smrg when a subobject of a class object is accessed without it.
162627f7eb2Smrg Note that it doesn't add the "_data" reference when the class container
163627f7eb2Smrg is the last element in the reference chain. */
164627f7eb2Smrg
165627f7eb2Smrg void
gfc_fix_class_refs(gfc_expr * e)166627f7eb2Smrg gfc_fix_class_refs (gfc_expr *e)
167627f7eb2Smrg {
168627f7eb2Smrg gfc_typespec *ts;
169627f7eb2Smrg gfc_ref **ref;
170627f7eb2Smrg
171627f7eb2Smrg if ((e->expr_type != EXPR_VARIABLE
172627f7eb2Smrg && e->expr_type != EXPR_FUNCTION)
173627f7eb2Smrg || (e->expr_type == EXPR_FUNCTION
174627f7eb2Smrg && e->value.function.isym != NULL))
175627f7eb2Smrg return;
176627f7eb2Smrg
177627f7eb2Smrg if (e->expr_type == EXPR_VARIABLE)
178627f7eb2Smrg ts = &e->symtree->n.sym->ts;
179627f7eb2Smrg else
180627f7eb2Smrg {
181627f7eb2Smrg gfc_symbol *func;
182627f7eb2Smrg
183627f7eb2Smrg gcc_assert (e->expr_type == EXPR_FUNCTION);
184627f7eb2Smrg if (e->value.function.esym != NULL)
185627f7eb2Smrg func = e->value.function.esym;
186627f7eb2Smrg else
187627f7eb2Smrg func = e->symtree->n.sym;
188627f7eb2Smrg
189627f7eb2Smrg if (func->result != NULL)
190627f7eb2Smrg ts = &func->result->ts;
191627f7eb2Smrg else
192627f7eb2Smrg ts = &func->ts;
193627f7eb2Smrg }
194627f7eb2Smrg
195627f7eb2Smrg for (ref = &e->ref; *ref != NULL; ref = &(*ref)->next)
196627f7eb2Smrg {
197627f7eb2Smrg if (class_data_ref_missing (ts, *ref, ref == &e->ref))
198627f7eb2Smrg insert_component_ref (ts, ref, "_data");
199627f7eb2Smrg
200627f7eb2Smrg if ((*ref)->type == REF_COMPONENT)
201627f7eb2Smrg ts = &(*ref)->u.c.component->ts;
202627f7eb2Smrg }
203627f7eb2Smrg }
204627f7eb2Smrg
205627f7eb2Smrg
206627f7eb2Smrg /* Insert a reference to the component of the given name.
207627f7eb2Smrg Only to be used with CLASS containers and vtables. */
208627f7eb2Smrg
209627f7eb2Smrg void
gfc_add_component_ref(gfc_expr * e,const char * name)210627f7eb2Smrg gfc_add_component_ref (gfc_expr *e, const char *name)
211627f7eb2Smrg {
212627f7eb2Smrg gfc_component *c;
213627f7eb2Smrg gfc_ref **tail = &(e->ref);
214627f7eb2Smrg gfc_ref *ref, *next = NULL;
215627f7eb2Smrg gfc_symbol *derived = e->symtree->n.sym->ts.u.derived;
216627f7eb2Smrg while (*tail != NULL)
217627f7eb2Smrg {
218627f7eb2Smrg if ((*tail)->type == REF_COMPONENT)
219627f7eb2Smrg {
220627f7eb2Smrg if (strcmp ((*tail)->u.c.component->name, "_data") == 0
221627f7eb2Smrg && (*tail)->next
222627f7eb2Smrg && (*tail)->next->type == REF_ARRAY
223627f7eb2Smrg && (*tail)->next->next == NULL)
224627f7eb2Smrg return;
225627f7eb2Smrg derived = (*tail)->u.c.component->ts.u.derived;
226627f7eb2Smrg }
227627f7eb2Smrg if ((*tail)->type == REF_ARRAY && (*tail)->next == NULL)
228627f7eb2Smrg break;
229627f7eb2Smrg tail = &((*tail)->next);
230627f7eb2Smrg }
231*4c3eb207Smrg if (derived && derived->components && derived->components->next &&
232627f7eb2Smrg derived->components->next->ts.type == BT_DERIVED &&
233627f7eb2Smrg derived->components->next->ts.u.derived == NULL)
234627f7eb2Smrg {
235627f7eb2Smrg /* Fix up missing vtype. */
236627f7eb2Smrg gfc_symbol *vtab = gfc_find_derived_vtab (derived->components->ts.u.derived);
237627f7eb2Smrg gcc_assert (vtab);
238627f7eb2Smrg derived->components->next->ts.u.derived = vtab->ts.u.derived;
239627f7eb2Smrg }
240627f7eb2Smrg if (*tail != NULL && strcmp (name, "_data") == 0)
241627f7eb2Smrg next = *tail;
242627f7eb2Smrg else
243627f7eb2Smrg /* Avoid losing memory. */
244627f7eb2Smrg gfc_free_ref_list (*tail);
245627f7eb2Smrg c = gfc_find_component (derived, name, true, true, tail);
246627f7eb2Smrg
247627f7eb2Smrg if (c) {
248627f7eb2Smrg for (ref = *tail; ref->next; ref = ref->next)
249627f7eb2Smrg ;
250627f7eb2Smrg ref->next = next;
251627f7eb2Smrg if (!next)
252627f7eb2Smrg e->ts = c->ts;
253627f7eb2Smrg }
254627f7eb2Smrg }
255627f7eb2Smrg
256627f7eb2Smrg
257627f7eb2Smrg /* This is used to add both the _data component reference and an array
258627f7eb2Smrg reference to class expressions. Used in translation of intrinsic
259627f7eb2Smrg array inquiry functions. */
260627f7eb2Smrg
261627f7eb2Smrg void
gfc_add_class_array_ref(gfc_expr * e)262627f7eb2Smrg gfc_add_class_array_ref (gfc_expr *e)
263627f7eb2Smrg {
264627f7eb2Smrg int rank = CLASS_DATA (e)->as->rank;
265627f7eb2Smrg gfc_array_spec *as = CLASS_DATA (e)->as;
266627f7eb2Smrg gfc_ref *ref = NULL;
267627f7eb2Smrg gfc_add_data_component (e);
268627f7eb2Smrg e->rank = rank;
269627f7eb2Smrg for (ref = e->ref; ref; ref = ref->next)
270627f7eb2Smrg if (!ref->next)
271627f7eb2Smrg break;
272627f7eb2Smrg if (ref->type != REF_ARRAY)
273627f7eb2Smrg {
274627f7eb2Smrg ref->next = gfc_get_ref ();
275627f7eb2Smrg ref = ref->next;
276627f7eb2Smrg ref->type = REF_ARRAY;
277627f7eb2Smrg ref->u.ar.type = AR_FULL;
278627f7eb2Smrg ref->u.ar.as = as;
279627f7eb2Smrg }
280627f7eb2Smrg }
281627f7eb2Smrg
282627f7eb2Smrg
283627f7eb2Smrg /* Unfortunately, class array expressions can appear in various conditions;
284627f7eb2Smrg with and without both _data component and an arrayspec. This function
285627f7eb2Smrg deals with that variability. The previous reference to 'ref' is to a
286627f7eb2Smrg class array. */
287627f7eb2Smrg
288627f7eb2Smrg static bool
class_array_ref_detected(gfc_ref * ref,bool * full_array)289627f7eb2Smrg class_array_ref_detected (gfc_ref *ref, bool *full_array)
290627f7eb2Smrg {
291627f7eb2Smrg bool no_data = false;
292627f7eb2Smrg bool with_data = false;
293627f7eb2Smrg
294627f7eb2Smrg /* An array reference with no _data component. */
295627f7eb2Smrg if (ref && ref->type == REF_ARRAY
296627f7eb2Smrg && !ref->next
297627f7eb2Smrg && ref->u.ar.type != AR_ELEMENT)
298627f7eb2Smrg {
299627f7eb2Smrg if (full_array)
300627f7eb2Smrg *full_array = ref->u.ar.type == AR_FULL;
301627f7eb2Smrg no_data = true;
302627f7eb2Smrg }
303627f7eb2Smrg
304627f7eb2Smrg /* Cover cases where _data appears, with or without an array ref. */
305627f7eb2Smrg if (ref && ref->type == REF_COMPONENT
306627f7eb2Smrg && strcmp (ref->u.c.component->name, "_data") == 0)
307627f7eb2Smrg {
308627f7eb2Smrg if (!ref->next)
309627f7eb2Smrg {
310627f7eb2Smrg with_data = true;
311627f7eb2Smrg if (full_array)
312627f7eb2Smrg *full_array = true;
313627f7eb2Smrg }
314627f7eb2Smrg else if (ref->next && ref->next->type == REF_ARRAY
315627f7eb2Smrg && ref->type == REF_COMPONENT
316627f7eb2Smrg && ref->next->u.ar.type != AR_ELEMENT)
317627f7eb2Smrg {
318627f7eb2Smrg with_data = true;
319627f7eb2Smrg if (full_array)
320627f7eb2Smrg *full_array = ref->next->u.ar.type == AR_FULL;
321627f7eb2Smrg }
322627f7eb2Smrg }
323627f7eb2Smrg
324627f7eb2Smrg return no_data || with_data;
325627f7eb2Smrg }
326627f7eb2Smrg
327627f7eb2Smrg
328627f7eb2Smrg /* Returns true if the expression contains a reference to a class
329627f7eb2Smrg array. Notice that class array elements return false. */
330627f7eb2Smrg
331627f7eb2Smrg bool
gfc_is_class_array_ref(gfc_expr * e,bool * full_array)332627f7eb2Smrg gfc_is_class_array_ref (gfc_expr *e, bool *full_array)
333627f7eb2Smrg {
334627f7eb2Smrg gfc_ref *ref;
335627f7eb2Smrg
336627f7eb2Smrg if (!e->rank)
337627f7eb2Smrg return false;
338627f7eb2Smrg
339627f7eb2Smrg if (full_array)
340627f7eb2Smrg *full_array= false;
341627f7eb2Smrg
342627f7eb2Smrg /* Is this a class array object? ie. Is the symbol of type class? */
343627f7eb2Smrg if (e->symtree
344627f7eb2Smrg && e->symtree->n.sym->ts.type == BT_CLASS
345627f7eb2Smrg && CLASS_DATA (e->symtree->n.sym)
346627f7eb2Smrg && CLASS_DATA (e->symtree->n.sym)->attr.dimension
347627f7eb2Smrg && class_array_ref_detected (e->ref, full_array))
348627f7eb2Smrg return true;
349627f7eb2Smrg
350627f7eb2Smrg /* Or is this a class array component reference? */
351627f7eb2Smrg for (ref = e->ref; ref; ref = ref->next)
352627f7eb2Smrg {
353627f7eb2Smrg if (ref->type == REF_COMPONENT
354627f7eb2Smrg && ref->u.c.component->ts.type == BT_CLASS
355627f7eb2Smrg && CLASS_DATA (ref->u.c.component)->attr.dimension
356627f7eb2Smrg && class_array_ref_detected (ref->next, full_array))
357627f7eb2Smrg return true;
358627f7eb2Smrg }
359627f7eb2Smrg
360627f7eb2Smrg return false;
361627f7eb2Smrg }
362627f7eb2Smrg
363627f7eb2Smrg
364627f7eb2Smrg /* Returns true if the expression is a reference to a class
365627f7eb2Smrg scalar. This function is necessary because such expressions
366627f7eb2Smrg can be dressed with a reference to the _data component and so
367627f7eb2Smrg have a type other than BT_CLASS. */
368627f7eb2Smrg
369627f7eb2Smrg bool
gfc_is_class_scalar_expr(gfc_expr * e)370627f7eb2Smrg gfc_is_class_scalar_expr (gfc_expr *e)
371627f7eb2Smrg {
372627f7eb2Smrg gfc_ref *ref;
373627f7eb2Smrg
374627f7eb2Smrg if (e->rank)
375627f7eb2Smrg return false;
376627f7eb2Smrg
377627f7eb2Smrg /* Is this a class object? */
378627f7eb2Smrg if (e->symtree
379627f7eb2Smrg && e->symtree->n.sym->ts.type == BT_CLASS
380627f7eb2Smrg && CLASS_DATA (e->symtree->n.sym)
381627f7eb2Smrg && !CLASS_DATA (e->symtree->n.sym)->attr.dimension
382627f7eb2Smrg && (e->ref == NULL
383627f7eb2Smrg || (e->ref->type == REF_COMPONENT
384627f7eb2Smrg && strcmp (e->ref->u.c.component->name, "_data") == 0
385627f7eb2Smrg && e->ref->next == NULL)))
386627f7eb2Smrg return true;
387627f7eb2Smrg
388627f7eb2Smrg /* Or is the final reference BT_CLASS or _data? */
389627f7eb2Smrg for (ref = e->ref; ref; ref = ref->next)
390627f7eb2Smrg {
391627f7eb2Smrg if (ref->type == REF_COMPONENT
392627f7eb2Smrg && ref->u.c.component->ts.type == BT_CLASS
393627f7eb2Smrg && CLASS_DATA (ref->u.c.component)
394627f7eb2Smrg && !CLASS_DATA (ref->u.c.component)->attr.dimension
395627f7eb2Smrg && (ref->next == NULL
396627f7eb2Smrg || (ref->next->type == REF_COMPONENT
397627f7eb2Smrg && strcmp (ref->next->u.c.component->name, "_data") == 0
398627f7eb2Smrg && ref->next->next == NULL)))
399627f7eb2Smrg return true;
400627f7eb2Smrg }
401627f7eb2Smrg
402627f7eb2Smrg return false;
403627f7eb2Smrg }
404627f7eb2Smrg
405627f7eb2Smrg
406627f7eb2Smrg /* Tells whether the expression E is a reference to a (scalar) class container.
407627f7eb2Smrg Scalar because array class containers usually have an array reference after
408627f7eb2Smrg them, and gfc_fix_class_refs will add the missing "_data" component reference
409627f7eb2Smrg in that case. */
410627f7eb2Smrg
411627f7eb2Smrg bool
gfc_is_class_container_ref(gfc_expr * e)412627f7eb2Smrg gfc_is_class_container_ref (gfc_expr *e)
413627f7eb2Smrg {
414627f7eb2Smrg gfc_ref *ref;
415627f7eb2Smrg bool result;
416627f7eb2Smrg
417627f7eb2Smrg if (e->expr_type != EXPR_VARIABLE)
418627f7eb2Smrg return e->ts.type == BT_CLASS;
419627f7eb2Smrg
420627f7eb2Smrg if (e->symtree->n.sym->ts.type == BT_CLASS)
421627f7eb2Smrg result = true;
422627f7eb2Smrg else
423627f7eb2Smrg result = false;
424627f7eb2Smrg
425627f7eb2Smrg for (ref = e->ref; ref; ref = ref->next)
426627f7eb2Smrg {
427627f7eb2Smrg if (ref->type != REF_COMPONENT)
428627f7eb2Smrg result = false;
429627f7eb2Smrg else if (ref->u.c.component->ts.type == BT_CLASS)
430627f7eb2Smrg result = true;
431627f7eb2Smrg else
432627f7eb2Smrg result = false;
433627f7eb2Smrg }
434627f7eb2Smrg
435627f7eb2Smrg return result;
436627f7eb2Smrg }
437627f7eb2Smrg
438627f7eb2Smrg
439627f7eb2Smrg /* Build an initializer for CLASS pointers,
440627f7eb2Smrg initializing the _data component to the init_expr (or NULL) and the _vptr
441627f7eb2Smrg component to the corresponding type (or the declared type, given by ts). */
442627f7eb2Smrg
443627f7eb2Smrg gfc_expr *
gfc_class_initializer(gfc_typespec * ts,gfc_expr * init_expr)444627f7eb2Smrg gfc_class_initializer (gfc_typespec *ts, gfc_expr *init_expr)
445627f7eb2Smrg {
446627f7eb2Smrg gfc_expr *init;
447627f7eb2Smrg gfc_component *comp;
448627f7eb2Smrg gfc_symbol *vtab = NULL;
449627f7eb2Smrg
450627f7eb2Smrg if (init_expr && init_expr->expr_type != EXPR_NULL)
451627f7eb2Smrg vtab = gfc_find_vtab (&init_expr->ts);
452627f7eb2Smrg else
453627f7eb2Smrg vtab = gfc_find_vtab (ts);
454627f7eb2Smrg
455627f7eb2Smrg init = gfc_get_structure_constructor_expr (ts->type, ts->kind,
456627f7eb2Smrg &ts->u.derived->declared_at);
457627f7eb2Smrg init->ts = *ts;
458627f7eb2Smrg
459627f7eb2Smrg for (comp = ts->u.derived->components; comp; comp = comp->next)
460627f7eb2Smrg {
461627f7eb2Smrg gfc_constructor *ctor = gfc_constructor_get();
462627f7eb2Smrg if (strcmp (comp->name, "_vptr") == 0 && vtab)
463627f7eb2Smrg ctor->expr = gfc_lval_expr_from_sym (vtab);
464627f7eb2Smrg else if (init_expr && init_expr->expr_type != EXPR_NULL)
465627f7eb2Smrg ctor->expr = gfc_copy_expr (init_expr);
466627f7eb2Smrg else
467627f7eb2Smrg ctor->expr = gfc_get_null_expr (NULL);
468627f7eb2Smrg gfc_constructor_append (&init->value.constructor, ctor);
469627f7eb2Smrg }
470627f7eb2Smrg
471627f7eb2Smrg return init;
472627f7eb2Smrg }
473627f7eb2Smrg
474627f7eb2Smrg
475627f7eb2Smrg /* Create a unique string identifier for a derived type, composed of its name
476627f7eb2Smrg and module name. This is used to construct unique names for the class
477627f7eb2Smrg containers and vtab symbols. */
478627f7eb2Smrg
479*4c3eb207Smrg static char *
get_unique_type_string(gfc_symbol * derived)480*4c3eb207Smrg get_unique_type_string (gfc_symbol *derived)
481627f7eb2Smrg {
482*4c3eb207Smrg const char *dt_name;
483*4c3eb207Smrg char *string;
484*4c3eb207Smrg size_t len;
485627f7eb2Smrg if (derived->attr.unlimited_polymorphic)
486*4c3eb207Smrg dt_name = "STAR";
487627f7eb2Smrg else
488*4c3eb207Smrg dt_name = gfc_dt_upper_string (derived->name);
489*4c3eb207Smrg len = strlen (dt_name) + 2;
490627f7eb2Smrg if (derived->attr.unlimited_polymorphic)
491*4c3eb207Smrg {
492*4c3eb207Smrg string = XNEWVEC (char, len);
493627f7eb2Smrg sprintf (string, "_%s", dt_name);
494*4c3eb207Smrg }
495627f7eb2Smrg else if (derived->module)
496*4c3eb207Smrg {
497*4c3eb207Smrg string = XNEWVEC (char, strlen (derived->module) + len);
498627f7eb2Smrg sprintf (string, "%s_%s", derived->module, dt_name);
499*4c3eb207Smrg }
500627f7eb2Smrg else if (derived->ns->proc_name)
501*4c3eb207Smrg {
502*4c3eb207Smrg string = XNEWVEC (char, strlen (derived->ns->proc_name->name) + len);
503627f7eb2Smrg sprintf (string, "%s_%s", derived->ns->proc_name->name, dt_name);
504*4c3eb207Smrg }
505627f7eb2Smrg else
506*4c3eb207Smrg {
507*4c3eb207Smrg string = XNEWVEC (char, len);
508627f7eb2Smrg sprintf (string, "_%s", dt_name);
509627f7eb2Smrg }
510*4c3eb207Smrg return string;
511*4c3eb207Smrg }
512627f7eb2Smrg
513627f7eb2Smrg
514627f7eb2Smrg /* A relative of 'get_unique_type_string' which makes sure the generated
515627f7eb2Smrg string will not be too long (replacing it by a hash string if needed). */
516627f7eb2Smrg
517627f7eb2Smrg static void
get_unique_hashed_string(char * string,gfc_symbol * derived)518627f7eb2Smrg get_unique_hashed_string (char *string, gfc_symbol *derived)
519627f7eb2Smrg {
520*4c3eb207Smrg /* Provide sufficient space to hold "symbol.symbol_symbol". */
521*4c3eb207Smrg char *tmp;
522*4c3eb207Smrg tmp = get_unique_type_string (derived);
523627f7eb2Smrg /* If string is too long, use hash value in hex representation (allow for
524627f7eb2Smrg extra decoration, cf. gfc_build_class_symbol & gfc_find_derived_vtab).
525627f7eb2Smrg We need space to for 15 characters "__class_" + symbol name + "_%d_%da",
526627f7eb2Smrg where %d is the (co)rank which can be up to n = 15. */
527627f7eb2Smrg if (strlen (tmp) > GFC_MAX_SYMBOL_LEN - 15)
528627f7eb2Smrg {
529627f7eb2Smrg int h = gfc_hash_value (derived);
530627f7eb2Smrg sprintf (string, "%X", h);
531627f7eb2Smrg }
532627f7eb2Smrg else
533627f7eb2Smrg strcpy (string, tmp);
534*4c3eb207Smrg free (tmp);
535627f7eb2Smrg }
536627f7eb2Smrg
537627f7eb2Smrg
538627f7eb2Smrg /* Assign a hash value for a derived type. The algorithm is that of SDBM. */
539627f7eb2Smrg
540627f7eb2Smrg unsigned int
gfc_hash_value(gfc_symbol * sym)541627f7eb2Smrg gfc_hash_value (gfc_symbol *sym)
542627f7eb2Smrg {
543627f7eb2Smrg unsigned int hash = 0;
544*4c3eb207Smrg /* Provide sufficient space to hold "symbol.symbol_symbol". */
545*4c3eb207Smrg char *c;
546627f7eb2Smrg int i, len;
547627f7eb2Smrg
548*4c3eb207Smrg c = get_unique_type_string (sym);
549627f7eb2Smrg len = strlen (c);
550627f7eb2Smrg
551627f7eb2Smrg for (i = 0; i < len; i++)
552627f7eb2Smrg hash = (hash << 6) + (hash << 16) - hash + c[i];
553627f7eb2Smrg
554*4c3eb207Smrg free (c);
555627f7eb2Smrg /* Return the hash but take the modulus for the sake of module read,
556627f7eb2Smrg even though this slightly increases the chance of collision. */
557627f7eb2Smrg return (hash % 100000000);
558627f7eb2Smrg }
559627f7eb2Smrg
560627f7eb2Smrg
561627f7eb2Smrg /* Assign a hash value for an intrinsic type. The algorithm is that of SDBM. */
562627f7eb2Smrg
563627f7eb2Smrg unsigned int
gfc_intrinsic_hash_value(gfc_typespec * ts)564627f7eb2Smrg gfc_intrinsic_hash_value (gfc_typespec *ts)
565627f7eb2Smrg {
566627f7eb2Smrg unsigned int hash = 0;
567*4c3eb207Smrg const char *c = gfc_typename (ts, true);
568627f7eb2Smrg int i, len;
569627f7eb2Smrg
570627f7eb2Smrg len = strlen (c);
571627f7eb2Smrg
572627f7eb2Smrg for (i = 0; i < len; i++)
573627f7eb2Smrg hash = (hash << 6) + (hash << 16) - hash + c[i];
574627f7eb2Smrg
575627f7eb2Smrg /* Return the hash but take the modulus for the sake of module read,
576627f7eb2Smrg even though this slightly increases the chance of collision. */
577627f7eb2Smrg return (hash % 100000000);
578627f7eb2Smrg }
579627f7eb2Smrg
580627f7eb2Smrg
581627f7eb2Smrg /* Get the _len component from a class/derived object storing a string.
582627f7eb2Smrg For unlimited polymorphic entities a ref to the _data component is available
583627f7eb2Smrg while a ref to the _len component is needed. This routine traverese the
584627f7eb2Smrg ref-chain and strips the last ref to a _data from it replacing it with a
585627f7eb2Smrg ref to the _len component. */
586627f7eb2Smrg
587627f7eb2Smrg gfc_expr *
gfc_get_len_component(gfc_expr * e,int k)588627f7eb2Smrg gfc_get_len_component (gfc_expr *e, int k)
589627f7eb2Smrg {
590627f7eb2Smrg gfc_expr *ptr;
591627f7eb2Smrg gfc_ref *ref, **last;
592627f7eb2Smrg
593627f7eb2Smrg ptr = gfc_copy_expr (e);
594627f7eb2Smrg
595627f7eb2Smrg /* We need to remove the last _data component ref from ptr. */
596627f7eb2Smrg last = &(ptr->ref);
597627f7eb2Smrg ref = ptr->ref;
598627f7eb2Smrg while (ref)
599627f7eb2Smrg {
600627f7eb2Smrg if (!ref->next
601627f7eb2Smrg && ref->type == REF_COMPONENT
602627f7eb2Smrg && strcmp ("_data", ref->u.c.component->name)== 0)
603627f7eb2Smrg {
604627f7eb2Smrg gfc_free_ref_list (ref);
605627f7eb2Smrg *last = NULL;
606627f7eb2Smrg break;
607627f7eb2Smrg }
608627f7eb2Smrg last = &(ref->next);
609627f7eb2Smrg ref = ref->next;
610627f7eb2Smrg }
611627f7eb2Smrg /* And replace if with a ref to the _len component. */
612627f7eb2Smrg gfc_add_len_component (ptr);
613627f7eb2Smrg if (k != ptr->ts.kind)
614627f7eb2Smrg {
615627f7eb2Smrg gfc_typespec ts;
616627f7eb2Smrg gfc_clear_ts (&ts);
617627f7eb2Smrg ts.type = BT_INTEGER;
618627f7eb2Smrg ts.kind = k;
619627f7eb2Smrg gfc_convert_type_warn (ptr, &ts, 2, 0);
620627f7eb2Smrg }
621627f7eb2Smrg return ptr;
622627f7eb2Smrg }
623627f7eb2Smrg
624627f7eb2Smrg
625627f7eb2Smrg /* Build a polymorphic CLASS entity, using the symbol that comes from
626627f7eb2Smrg build_sym. A CLASS entity is represented by an encapsulating type,
627627f7eb2Smrg which contains the declared type as '_data' component, plus a pointer
628627f7eb2Smrg component '_vptr' which determines the dynamic type. When this CLASS
629627f7eb2Smrg entity is unlimited polymorphic, then also add a component '_len' to
630627f7eb2Smrg store the length of string when that is stored in it. */
631*4c3eb207Smrg static int ctr = 0;
632627f7eb2Smrg
633627f7eb2Smrg bool
gfc_build_class_symbol(gfc_typespec * ts,symbol_attribute * attr,gfc_array_spec ** as)634627f7eb2Smrg gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
635627f7eb2Smrg gfc_array_spec **as)
636627f7eb2Smrg {
637627f7eb2Smrg char tname[GFC_MAX_SYMBOL_LEN+1];
638627f7eb2Smrg char *name;
639627f7eb2Smrg gfc_symbol *fclass;
640627f7eb2Smrg gfc_symbol *vtab;
641627f7eb2Smrg gfc_component *c;
642627f7eb2Smrg gfc_namespace *ns;
643627f7eb2Smrg int rank;
644627f7eb2Smrg
645627f7eb2Smrg gcc_assert (as);
646627f7eb2Smrg
647627f7eb2Smrg if (attr->class_ok)
648627f7eb2Smrg /* Class container has already been built. */
649627f7eb2Smrg return true;
650627f7eb2Smrg
651627f7eb2Smrg attr->class_ok = attr->dummy || attr->pointer || attr->allocatable
652627f7eb2Smrg || attr->select_type_temporary || attr->associate_var;
653627f7eb2Smrg
654627f7eb2Smrg if (!attr->class_ok)
655627f7eb2Smrg /* We cannot build the class container yet. */
656627f7eb2Smrg return true;
657627f7eb2Smrg
658627f7eb2Smrg /* Determine the name of the encapsulating type. */
659627f7eb2Smrg rank = !(*as) || (*as)->rank == -1 ? GFC_MAX_DIMENSIONS : (*as)->rank;
660*4c3eb207Smrg
661*4c3eb207Smrg if (!ts->u.derived)
662*4c3eb207Smrg return false;
663*4c3eb207Smrg
664627f7eb2Smrg get_unique_hashed_string (tname, ts->u.derived);
665627f7eb2Smrg if ((*as) && attr->allocatable)
666627f7eb2Smrg name = xasprintf ("__class_%s_%d_%da", tname, rank, (*as)->corank);
667627f7eb2Smrg else if ((*as) && attr->pointer)
668627f7eb2Smrg name = xasprintf ("__class_%s_%d_%dp", tname, rank, (*as)->corank);
669627f7eb2Smrg else if ((*as))
670627f7eb2Smrg name = xasprintf ("__class_%s_%d_%dt", tname, rank, (*as)->corank);
671627f7eb2Smrg else if (attr->pointer)
672627f7eb2Smrg name = xasprintf ("__class_%s_p", tname);
673627f7eb2Smrg else if (attr->allocatable)
674627f7eb2Smrg name = xasprintf ("__class_%s_a", tname);
675627f7eb2Smrg else
676627f7eb2Smrg name = xasprintf ("__class_%s_t", tname);
677627f7eb2Smrg
678627f7eb2Smrg if (ts->u.derived->attr.unlimited_polymorphic)
679627f7eb2Smrg {
680627f7eb2Smrg /* Find the top-level namespace. */
681627f7eb2Smrg for (ns = gfc_current_ns; ns; ns = ns->parent)
682627f7eb2Smrg if (!ns->parent)
683627f7eb2Smrg break;
684627f7eb2Smrg }
685627f7eb2Smrg else
686627f7eb2Smrg ns = ts->u.derived->ns;
687627f7eb2Smrg
688*4c3eb207Smrg /* Although this might seem to be counterintuitive, we can build separate
689*4c3eb207Smrg class types with different array specs because the TKR interface checks
690*4c3eb207Smrg work on the declared type. All array type other than deferred shape or
691*4c3eb207Smrg assumed rank are added to the function namespace to ensure that they
692*4c3eb207Smrg are properly distinguished. */
693*4c3eb207Smrg if (attr->dummy && !attr->codimension && (*as)
694*4c3eb207Smrg && !((*as)->type == AS_DEFERRED || (*as)->type == AS_ASSUMED_RANK))
695*4c3eb207Smrg {
696*4c3eb207Smrg char *sname;
697*4c3eb207Smrg ns = gfc_current_ns;
698627f7eb2Smrg gfc_find_symbol (name, ns, 0, &fclass);
699*4c3eb207Smrg /* If a local class type with this name already exists, update the
700*4c3eb207Smrg name with an index. */
701*4c3eb207Smrg if (fclass)
702*4c3eb207Smrg {
703*4c3eb207Smrg fclass = NULL;
704*4c3eb207Smrg sname = xasprintf ("%s_%d", name, ++ctr);
705*4c3eb207Smrg free (name);
706*4c3eb207Smrg name = sname;
707*4c3eb207Smrg }
708*4c3eb207Smrg }
709*4c3eb207Smrg else
710*4c3eb207Smrg gfc_find_symbol (name, ns, 0, &fclass);
711*4c3eb207Smrg
712627f7eb2Smrg if (fclass == NULL)
713627f7eb2Smrg {
714627f7eb2Smrg gfc_symtree *st;
715627f7eb2Smrg /* If not there, create a new symbol. */
716627f7eb2Smrg fclass = gfc_new_symbol (name, ns);
717627f7eb2Smrg st = gfc_new_symtree (&ns->sym_root, name);
718627f7eb2Smrg st->n.sym = fclass;
719627f7eb2Smrg gfc_set_sym_referenced (fclass);
720627f7eb2Smrg fclass->refs++;
721627f7eb2Smrg fclass->ts.type = BT_UNKNOWN;
722627f7eb2Smrg if (!ts->u.derived->attr.unlimited_polymorphic)
723627f7eb2Smrg fclass->attr.abstract = ts->u.derived->attr.abstract;
724627f7eb2Smrg fclass->f2k_derived = gfc_get_namespace (NULL, 0);
725627f7eb2Smrg if (!gfc_add_flavor (&fclass->attr, FL_DERIVED, NULL,
726627f7eb2Smrg &gfc_current_locus))
727627f7eb2Smrg return false;
728627f7eb2Smrg
729627f7eb2Smrg /* Add component '_data'. */
730627f7eb2Smrg if (!gfc_add_component (fclass, "_data", &c))
731627f7eb2Smrg return false;
732627f7eb2Smrg c->ts = *ts;
733627f7eb2Smrg c->ts.type = BT_DERIVED;
734627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
735627f7eb2Smrg c->ts.u.derived = ts->u.derived;
736627f7eb2Smrg c->attr.class_pointer = attr->pointer;
737627f7eb2Smrg c->attr.pointer = attr->pointer || (attr->dummy && !attr->allocatable)
738627f7eb2Smrg || attr->select_type_temporary;
739627f7eb2Smrg c->attr.allocatable = attr->allocatable;
740627f7eb2Smrg c->attr.dimension = attr->dimension;
741627f7eb2Smrg c->attr.codimension = attr->codimension;
742627f7eb2Smrg c->attr.abstract = fclass->attr.abstract;
743627f7eb2Smrg c->as = (*as);
744627f7eb2Smrg c->initializer = NULL;
745627f7eb2Smrg
746627f7eb2Smrg /* Add component '_vptr'. */
747627f7eb2Smrg if (!gfc_add_component (fclass, "_vptr", &c))
748627f7eb2Smrg return false;
749627f7eb2Smrg c->ts.type = BT_DERIVED;
750627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
751627f7eb2Smrg c->attr.pointer = 1;
752627f7eb2Smrg
753627f7eb2Smrg if (ts->u.derived->attr.unlimited_polymorphic)
754627f7eb2Smrg {
755627f7eb2Smrg vtab = gfc_find_derived_vtab (ts->u.derived);
756627f7eb2Smrg gcc_assert (vtab);
757627f7eb2Smrg c->ts.u.derived = vtab->ts.u.derived;
758627f7eb2Smrg
759627f7eb2Smrg /* Add component '_len'. Only unlimited polymorphic pointers may
760627f7eb2Smrg have a string assigned to them, i.e., only those need the _len
761627f7eb2Smrg component. */
762627f7eb2Smrg if (!gfc_add_component (fclass, "_len", &c))
763627f7eb2Smrg return false;
764627f7eb2Smrg c->ts.type = BT_INTEGER;
765627f7eb2Smrg c->ts.kind = gfc_charlen_int_kind;
766627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
767627f7eb2Smrg c->attr.artificial = 1;
768627f7eb2Smrg }
769627f7eb2Smrg else
770627f7eb2Smrg /* Build vtab later. */
771627f7eb2Smrg c->ts.u.derived = NULL;
772627f7eb2Smrg }
773627f7eb2Smrg
774627f7eb2Smrg if (!ts->u.derived->attr.unlimited_polymorphic)
775627f7eb2Smrg {
776627f7eb2Smrg /* Since the extension field is 8 bit wide, we can only have
777627f7eb2Smrg up to 255 extension levels. */
778627f7eb2Smrg if (ts->u.derived->attr.extension == 255)
779627f7eb2Smrg {
780627f7eb2Smrg gfc_error ("Maximum extension level reached with type %qs at %L",
781627f7eb2Smrg ts->u.derived->name, &ts->u.derived->declared_at);
782627f7eb2Smrg return false;
783627f7eb2Smrg }
784627f7eb2Smrg
785627f7eb2Smrg fclass->attr.extension = ts->u.derived->attr.extension + 1;
786627f7eb2Smrg fclass->attr.alloc_comp = ts->u.derived->attr.alloc_comp;
787627f7eb2Smrg fclass->attr.coarray_comp = ts->u.derived->attr.coarray_comp;
788627f7eb2Smrg }
789627f7eb2Smrg
790627f7eb2Smrg fclass->attr.is_class = 1;
791627f7eb2Smrg ts->u.derived = fclass;
792627f7eb2Smrg attr->allocatable = attr->pointer = attr->dimension = attr->codimension = 0;
793627f7eb2Smrg (*as) = NULL;
794627f7eb2Smrg free (name);
795627f7eb2Smrg return true;
796627f7eb2Smrg }
797627f7eb2Smrg
798627f7eb2Smrg
799627f7eb2Smrg /* Add a procedure pointer component to the vtype
800627f7eb2Smrg to represent a specific type-bound procedure. */
801627f7eb2Smrg
802627f7eb2Smrg static void
add_proc_comp(gfc_symbol * vtype,const char * name,gfc_typebound_proc * tb)803627f7eb2Smrg add_proc_comp (gfc_symbol *vtype, const char *name, gfc_typebound_proc *tb)
804627f7eb2Smrg {
805627f7eb2Smrg gfc_component *c;
806627f7eb2Smrg
807627f7eb2Smrg if (tb->non_overridable && !tb->overridden)
808627f7eb2Smrg return;
809627f7eb2Smrg
810627f7eb2Smrg c = gfc_find_component (vtype, name, true, true, NULL);
811627f7eb2Smrg
812627f7eb2Smrg if (c == NULL)
813627f7eb2Smrg {
814627f7eb2Smrg /* Add procedure component. */
815627f7eb2Smrg if (!gfc_add_component (vtype, name, &c))
816627f7eb2Smrg return;
817627f7eb2Smrg
818627f7eb2Smrg if (!c->tb)
819627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
820627f7eb2Smrg *c->tb = *tb;
821627f7eb2Smrg c->tb->ppc = 1;
822627f7eb2Smrg c->attr.procedure = 1;
823627f7eb2Smrg c->attr.proc_pointer = 1;
824627f7eb2Smrg c->attr.flavor = FL_PROCEDURE;
825627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
826627f7eb2Smrg c->attr.external = 1;
827627f7eb2Smrg c->attr.untyped = 1;
828627f7eb2Smrg c->attr.if_source = IFSRC_IFBODY;
829627f7eb2Smrg }
830627f7eb2Smrg else if (c->attr.proc_pointer && c->tb)
831627f7eb2Smrg {
832627f7eb2Smrg *c->tb = *tb;
833627f7eb2Smrg c->tb->ppc = 1;
834627f7eb2Smrg }
835627f7eb2Smrg
836627f7eb2Smrg if (tb->u.specific)
837627f7eb2Smrg {
838627f7eb2Smrg gfc_symbol *ifc = tb->u.specific->n.sym;
839627f7eb2Smrg c->ts.interface = ifc;
840627f7eb2Smrg if (!tb->deferred)
841627f7eb2Smrg c->initializer = gfc_get_variable_expr (tb->u.specific);
842627f7eb2Smrg c->attr.pure = ifc->attr.pure;
843627f7eb2Smrg }
844627f7eb2Smrg }
845627f7eb2Smrg
846627f7eb2Smrg
847627f7eb2Smrg /* Add all specific type-bound procedures in the symtree 'st' to a vtype. */
848627f7eb2Smrg
849627f7eb2Smrg static void
add_procs_to_declared_vtab1(gfc_symtree * st,gfc_symbol * vtype)850627f7eb2Smrg add_procs_to_declared_vtab1 (gfc_symtree *st, gfc_symbol *vtype)
851627f7eb2Smrg {
852627f7eb2Smrg if (!st)
853627f7eb2Smrg return;
854627f7eb2Smrg
855627f7eb2Smrg if (st->left)
856627f7eb2Smrg add_procs_to_declared_vtab1 (st->left, vtype);
857627f7eb2Smrg
858627f7eb2Smrg if (st->right)
859627f7eb2Smrg add_procs_to_declared_vtab1 (st->right, vtype);
860627f7eb2Smrg
861627f7eb2Smrg if (st->n.tb && !st->n.tb->error
862627f7eb2Smrg && !st->n.tb->is_generic && st->n.tb->u.specific)
863627f7eb2Smrg add_proc_comp (vtype, st->name, st->n.tb);
864627f7eb2Smrg }
865627f7eb2Smrg
866627f7eb2Smrg
867627f7eb2Smrg /* Copy procedure pointers components from the parent type. */
868627f7eb2Smrg
869627f7eb2Smrg static void
copy_vtab_proc_comps(gfc_symbol * declared,gfc_symbol * vtype)870627f7eb2Smrg copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol *vtype)
871627f7eb2Smrg {
872627f7eb2Smrg gfc_component *cmp;
873627f7eb2Smrg gfc_symbol *vtab;
874627f7eb2Smrg
875627f7eb2Smrg vtab = gfc_find_derived_vtab (declared);
876627f7eb2Smrg
877627f7eb2Smrg for (cmp = vtab->ts.u.derived->components; cmp; cmp = cmp->next)
878627f7eb2Smrg {
879627f7eb2Smrg if (gfc_find_component (vtype, cmp->name, true, true, NULL))
880627f7eb2Smrg continue;
881627f7eb2Smrg
882627f7eb2Smrg add_proc_comp (vtype, cmp->name, cmp->tb);
883627f7eb2Smrg }
884627f7eb2Smrg }
885627f7eb2Smrg
886627f7eb2Smrg
887627f7eb2Smrg /* Returns true if any of its nonpointer nonallocatable components or
888627f7eb2Smrg their nonpointer nonallocatable subcomponents has a finalization
889627f7eb2Smrg subroutine. */
890627f7eb2Smrg
891627f7eb2Smrg static bool
has_finalizer_component(gfc_symbol * derived)892627f7eb2Smrg has_finalizer_component (gfc_symbol *derived)
893627f7eb2Smrg {
894627f7eb2Smrg gfc_component *c;
895627f7eb2Smrg
896627f7eb2Smrg for (c = derived->components; c; c = c->next)
897627f7eb2Smrg if (c->ts.type == BT_DERIVED && !c->attr.pointer && !c->attr.allocatable)
898627f7eb2Smrg {
899627f7eb2Smrg if (c->ts.u.derived->f2k_derived
900627f7eb2Smrg && c->ts.u.derived->f2k_derived->finalizers)
901627f7eb2Smrg return true;
902627f7eb2Smrg
903627f7eb2Smrg /* Stop infinite recursion through this function by inhibiting
904627f7eb2Smrg calls when the derived type and that of the component are
905627f7eb2Smrg the same. */
906627f7eb2Smrg if (!gfc_compare_derived_types (derived, c->ts.u.derived)
907627f7eb2Smrg && has_finalizer_component (c->ts.u.derived))
908627f7eb2Smrg return true;
909627f7eb2Smrg }
910627f7eb2Smrg return false;
911627f7eb2Smrg }
912627f7eb2Smrg
913627f7eb2Smrg
914627f7eb2Smrg static bool
comp_is_finalizable(gfc_component * comp)915627f7eb2Smrg comp_is_finalizable (gfc_component *comp)
916627f7eb2Smrg {
917627f7eb2Smrg if (comp->attr.proc_pointer)
918627f7eb2Smrg return false;
919627f7eb2Smrg else if (comp->attr.allocatable && comp->ts.type != BT_CLASS)
920627f7eb2Smrg return true;
921627f7eb2Smrg else if (comp->ts.type == BT_DERIVED && !comp->attr.pointer
922627f7eb2Smrg && (comp->ts.u.derived->attr.alloc_comp
923627f7eb2Smrg || has_finalizer_component (comp->ts.u.derived)
924627f7eb2Smrg || (comp->ts.u.derived->f2k_derived
925627f7eb2Smrg && comp->ts.u.derived->f2k_derived->finalizers)))
926627f7eb2Smrg return true;
927627f7eb2Smrg else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
928627f7eb2Smrg && CLASS_DATA (comp)->attr.allocatable)
929627f7eb2Smrg return true;
930627f7eb2Smrg else
931627f7eb2Smrg return false;
932627f7eb2Smrg }
933627f7eb2Smrg
934627f7eb2Smrg
935627f7eb2Smrg /* Call DEALLOCATE for the passed component if it is allocatable, if it is
936627f7eb2Smrg neither allocatable nor a pointer but has a finalizer, call it. If it
937627f7eb2Smrg is a nonpointer component with allocatable components or has finalizers, walk
938627f7eb2Smrg them. Either of them is required; other nonallocatables and pointers aren't
939627f7eb2Smrg handled gracefully.
940627f7eb2Smrg Note: If the component is allocatable, the DEALLOCATE handling takes care
941627f7eb2Smrg of calling the appropriate finalizers, coarray deregistering, and
942627f7eb2Smrg deallocation of allocatable subcomponents. */
943627f7eb2Smrg
944627f7eb2Smrg static void
finalize_component(gfc_expr * expr,gfc_symbol * derived,gfc_component * comp,gfc_symbol * stat,gfc_symbol * fini_coarray,gfc_code ** code,gfc_namespace * sub_ns)945627f7eb2Smrg finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
946627f7eb2Smrg gfc_symbol *stat, gfc_symbol *fini_coarray, gfc_code **code,
947627f7eb2Smrg gfc_namespace *sub_ns)
948627f7eb2Smrg {
949627f7eb2Smrg gfc_expr *e;
950627f7eb2Smrg gfc_ref *ref;
951*4c3eb207Smrg gfc_was_finalized *f;
952627f7eb2Smrg
953627f7eb2Smrg if (!comp_is_finalizable (comp))
954627f7eb2Smrg return;
955627f7eb2Smrg
956*4c3eb207Smrg /* If this expression with this component has been finalized
957*4c3eb207Smrg already in this namespace, there is nothing to do. */
958*4c3eb207Smrg for (f = sub_ns->was_finalized; f; f = f->next)
959*4c3eb207Smrg {
960*4c3eb207Smrg if (f->e == expr && f->c == comp)
961627f7eb2Smrg return;
962*4c3eb207Smrg }
963627f7eb2Smrg
964627f7eb2Smrg e = gfc_copy_expr (expr);
965627f7eb2Smrg if (!e->ref)
966627f7eb2Smrg e->ref = ref = gfc_get_ref ();
967627f7eb2Smrg else
968627f7eb2Smrg {
969627f7eb2Smrg for (ref = e->ref; ref->next; ref = ref->next)
970627f7eb2Smrg ;
971627f7eb2Smrg ref->next = gfc_get_ref ();
972627f7eb2Smrg ref = ref->next;
973627f7eb2Smrg }
974627f7eb2Smrg ref->type = REF_COMPONENT;
975627f7eb2Smrg ref->u.c.sym = derived;
976627f7eb2Smrg ref->u.c.component = comp;
977627f7eb2Smrg e->ts = comp->ts;
978627f7eb2Smrg
979627f7eb2Smrg if (comp->attr.dimension || comp->attr.codimension
980627f7eb2Smrg || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
981627f7eb2Smrg && (CLASS_DATA (comp)->attr.dimension
982627f7eb2Smrg || CLASS_DATA (comp)->attr.codimension)))
983627f7eb2Smrg {
984627f7eb2Smrg ref->next = gfc_get_ref ();
985627f7eb2Smrg ref->next->type = REF_ARRAY;
986627f7eb2Smrg ref->next->u.ar.dimen = 0;
987627f7eb2Smrg ref->next->u.ar.as = comp->ts.type == BT_CLASS ? CLASS_DATA (comp)->as
988627f7eb2Smrg : comp->as;
989627f7eb2Smrg e->rank = ref->next->u.ar.as->rank;
990627f7eb2Smrg ref->next->u.ar.type = e->rank ? AR_FULL : AR_ELEMENT;
991627f7eb2Smrg }
992627f7eb2Smrg
993627f7eb2Smrg /* Call DEALLOCATE (comp, stat=ignore). */
994627f7eb2Smrg if (comp->attr.allocatable
995627f7eb2Smrg || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
996627f7eb2Smrg && CLASS_DATA (comp)->attr.allocatable))
997627f7eb2Smrg {
998627f7eb2Smrg gfc_code *dealloc, *block = NULL;
999627f7eb2Smrg
1000627f7eb2Smrg /* Add IF (fini_coarray). */
1001627f7eb2Smrg if (comp->attr.codimension
1002627f7eb2Smrg || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
1003627f7eb2Smrg && CLASS_DATA (comp)->attr.codimension))
1004627f7eb2Smrg {
1005627f7eb2Smrg block = gfc_get_code (EXEC_IF);
1006627f7eb2Smrg if (*code)
1007627f7eb2Smrg {
1008627f7eb2Smrg (*code)->next = block;
1009627f7eb2Smrg (*code) = (*code)->next;
1010627f7eb2Smrg }
1011627f7eb2Smrg else
1012627f7eb2Smrg (*code) = block;
1013627f7eb2Smrg
1014627f7eb2Smrg block->block = gfc_get_code (EXEC_IF);
1015627f7eb2Smrg block = block->block;
1016627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (fini_coarray);
1017627f7eb2Smrg }
1018627f7eb2Smrg
1019627f7eb2Smrg dealloc = gfc_get_code (EXEC_DEALLOCATE);
1020627f7eb2Smrg
1021627f7eb2Smrg dealloc->ext.alloc.list = gfc_get_alloc ();
1022627f7eb2Smrg dealloc->ext.alloc.list->expr = e;
1023627f7eb2Smrg dealloc->expr1 = gfc_lval_expr_from_sym (stat);
1024627f7eb2Smrg
1025627f7eb2Smrg gfc_code *cond = gfc_get_code (EXEC_IF);
1026627f7eb2Smrg cond->block = gfc_get_code (EXEC_IF);
1027627f7eb2Smrg cond->block->expr1 = gfc_get_expr ();
1028627f7eb2Smrg cond->block->expr1->expr_type = EXPR_FUNCTION;
1029627f7eb2Smrg cond->block->expr1->where = gfc_current_locus;
1030627f7eb2Smrg gfc_get_sym_tree ("associated", sub_ns, &cond->block->expr1->symtree, false);
1031627f7eb2Smrg cond->block->expr1->symtree->n.sym->attr.flavor = FL_PROCEDURE;
1032627f7eb2Smrg cond->block->expr1->symtree->n.sym->attr.intrinsic = 1;
1033627f7eb2Smrg cond->block->expr1->symtree->n.sym->result = cond->block->expr1->symtree->n.sym;
1034627f7eb2Smrg gfc_commit_symbol (cond->block->expr1->symtree->n.sym);
1035627f7eb2Smrg cond->block->expr1->ts.type = BT_LOGICAL;
1036627f7eb2Smrg cond->block->expr1->ts.kind = gfc_default_logical_kind;
1037627f7eb2Smrg cond->block->expr1->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_ASSOCIATED);
1038627f7eb2Smrg cond->block->expr1->value.function.actual = gfc_get_actual_arglist ();
1039627f7eb2Smrg cond->block->expr1->value.function.actual->expr = gfc_copy_expr (expr);
1040627f7eb2Smrg cond->block->expr1->value.function.actual->next = gfc_get_actual_arglist ();
1041627f7eb2Smrg cond->block->next = dealloc;
1042627f7eb2Smrg
1043627f7eb2Smrg if (block)
1044627f7eb2Smrg block->next = cond;
1045627f7eb2Smrg else if (*code)
1046627f7eb2Smrg {
1047627f7eb2Smrg (*code)->next = cond;
1048627f7eb2Smrg (*code) = (*code)->next;
1049627f7eb2Smrg }
1050627f7eb2Smrg else
1051627f7eb2Smrg (*code) = cond;
1052*4c3eb207Smrg
1053627f7eb2Smrg }
1054627f7eb2Smrg else if (comp->ts.type == BT_DERIVED
1055627f7eb2Smrg && comp->ts.u.derived->f2k_derived
1056627f7eb2Smrg && comp->ts.u.derived->f2k_derived->finalizers)
1057627f7eb2Smrg {
1058627f7eb2Smrg /* Call FINAL_WRAPPER (comp); */
1059627f7eb2Smrg gfc_code *final_wrap;
1060627f7eb2Smrg gfc_symbol *vtab;
1061627f7eb2Smrg gfc_component *c;
1062627f7eb2Smrg
1063627f7eb2Smrg vtab = gfc_find_derived_vtab (comp->ts.u.derived);
1064627f7eb2Smrg for (c = vtab->ts.u.derived->components; c; c = c->next)
1065627f7eb2Smrg if (strcmp (c->name, "_final") == 0)
1066627f7eb2Smrg break;
1067627f7eb2Smrg
1068627f7eb2Smrg gcc_assert (c);
1069627f7eb2Smrg final_wrap = gfc_get_code (EXEC_CALL);
1070627f7eb2Smrg final_wrap->symtree = c->initializer->symtree;
1071627f7eb2Smrg final_wrap->resolved_sym = c->initializer->symtree->n.sym;
1072627f7eb2Smrg final_wrap->ext.actual = gfc_get_actual_arglist ();
1073627f7eb2Smrg final_wrap->ext.actual->expr = e;
1074627f7eb2Smrg
1075627f7eb2Smrg if (*code)
1076627f7eb2Smrg {
1077627f7eb2Smrg (*code)->next = final_wrap;
1078627f7eb2Smrg (*code) = (*code)->next;
1079627f7eb2Smrg }
1080627f7eb2Smrg else
1081627f7eb2Smrg (*code) = final_wrap;
1082627f7eb2Smrg }
1083627f7eb2Smrg else
1084627f7eb2Smrg {
1085627f7eb2Smrg gfc_component *c;
1086627f7eb2Smrg
1087627f7eb2Smrg for (c = comp->ts.u.derived->components; c; c = c->next)
1088627f7eb2Smrg finalize_component (e, comp->ts.u.derived, c, stat, fini_coarray, code,
1089627f7eb2Smrg sub_ns);
1090627f7eb2Smrg gfc_free_expr (e);
1091627f7eb2Smrg }
1092*4c3eb207Smrg
1093*4c3eb207Smrg /* Record that this was finalized already in this namespace. */
1094*4c3eb207Smrg f = sub_ns->was_finalized;
1095*4c3eb207Smrg sub_ns->was_finalized = XCNEW (gfc_was_finalized);
1096*4c3eb207Smrg sub_ns->was_finalized->e = expr;
1097*4c3eb207Smrg sub_ns->was_finalized->c = comp;
1098*4c3eb207Smrg sub_ns->was_finalized->next = f;
1099627f7eb2Smrg }
1100627f7eb2Smrg
1101627f7eb2Smrg
1102627f7eb2Smrg /* Generate code equivalent to
1103627f7eb2Smrg CALL C_F_POINTER (TRANSFER (TRANSFER (C_LOC (array, cptr), c_intptr)
1104627f7eb2Smrg + offset, c_ptr), ptr). */
1105627f7eb2Smrg
1106627f7eb2Smrg static gfc_code *
finalization_scalarizer(gfc_symbol * array,gfc_symbol * ptr,gfc_expr * offset,gfc_namespace * sub_ns)1107627f7eb2Smrg finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
1108627f7eb2Smrg gfc_expr *offset, gfc_namespace *sub_ns)
1109627f7eb2Smrg {
1110627f7eb2Smrg gfc_code *block;
1111627f7eb2Smrg gfc_expr *expr, *expr2;
1112627f7eb2Smrg
1113627f7eb2Smrg /* C_F_POINTER(). */
1114627f7eb2Smrg block = gfc_get_code (EXEC_CALL);
1115627f7eb2Smrg gfc_get_sym_tree ("c_f_pointer", sub_ns, &block->symtree, true);
1116627f7eb2Smrg block->resolved_sym = block->symtree->n.sym;
1117627f7eb2Smrg block->resolved_sym->attr.flavor = FL_PROCEDURE;
1118627f7eb2Smrg block->resolved_sym->attr.intrinsic = 1;
1119627f7eb2Smrg block->resolved_sym->attr.subroutine = 1;
1120627f7eb2Smrg block->resolved_sym->from_intmod = INTMOD_ISO_C_BINDING;
1121627f7eb2Smrg block->resolved_sym->intmod_sym_id = ISOCBINDING_F_POINTER;
1122627f7eb2Smrg block->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_C_F_POINTER);
1123627f7eb2Smrg gfc_commit_symbol (block->resolved_sym);
1124627f7eb2Smrg
1125627f7eb2Smrg /* C_F_POINTER's first argument: TRANSFER ( <addr>, c_intptr_t). */
1126627f7eb2Smrg block->ext.actual = gfc_get_actual_arglist ();
1127627f7eb2Smrg block->ext.actual->next = gfc_get_actual_arglist ();
1128627f7eb2Smrg block->ext.actual->next->expr = gfc_get_int_expr (gfc_index_integer_kind,
1129627f7eb2Smrg NULL, 0);
1130627f7eb2Smrg block->ext.actual->next->next = gfc_get_actual_arglist (); /* SIZE. */
1131627f7eb2Smrg
1132627f7eb2Smrg /* The <addr> part: TRANSFER (C_LOC (array), c_intptr_t). */
1133627f7eb2Smrg
1134627f7eb2Smrg /* TRANSFER's first argument: C_LOC (array). */
1135627f7eb2Smrg expr = gfc_get_expr ();
1136627f7eb2Smrg expr->expr_type = EXPR_FUNCTION;
1137627f7eb2Smrg gfc_get_sym_tree ("c_loc", sub_ns, &expr->symtree, false);
1138627f7eb2Smrg expr->symtree->n.sym->attr.flavor = FL_PROCEDURE;
1139627f7eb2Smrg expr->symtree->n.sym->intmod_sym_id = ISOCBINDING_LOC;
1140627f7eb2Smrg expr->symtree->n.sym->attr.intrinsic = 1;
1141627f7eb2Smrg expr->symtree->n.sym->from_intmod = INTMOD_ISO_C_BINDING;
1142627f7eb2Smrg expr->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_C_LOC);
1143627f7eb2Smrg expr->value.function.actual = gfc_get_actual_arglist ();
1144627f7eb2Smrg expr->value.function.actual->expr
1145627f7eb2Smrg = gfc_lval_expr_from_sym (array);
1146627f7eb2Smrg expr->symtree->n.sym->result = expr->symtree->n.sym;
1147627f7eb2Smrg gfc_commit_symbol (expr->symtree->n.sym);
1148627f7eb2Smrg expr->ts.type = BT_INTEGER;
1149627f7eb2Smrg expr->ts.kind = gfc_index_integer_kind;
1150627f7eb2Smrg expr->where = gfc_current_locus;
1151627f7eb2Smrg
1152627f7eb2Smrg /* TRANSFER. */
1153627f7eb2Smrg expr2 = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_TRANSFER, "transfer",
1154627f7eb2Smrg gfc_current_locus, 3, expr,
1155627f7eb2Smrg gfc_get_int_expr (gfc_index_integer_kind,
1156627f7eb2Smrg NULL, 0), NULL);
1157627f7eb2Smrg expr2->ts.type = BT_INTEGER;
1158627f7eb2Smrg expr2->ts.kind = gfc_index_integer_kind;
1159627f7eb2Smrg
1160627f7eb2Smrg /* <array addr> + <offset>. */
1161627f7eb2Smrg block->ext.actual->expr = gfc_get_expr ();
1162627f7eb2Smrg block->ext.actual->expr->expr_type = EXPR_OP;
1163627f7eb2Smrg block->ext.actual->expr->value.op.op = INTRINSIC_PLUS;
1164627f7eb2Smrg block->ext.actual->expr->value.op.op1 = expr2;
1165627f7eb2Smrg block->ext.actual->expr->value.op.op2 = offset;
1166627f7eb2Smrg block->ext.actual->expr->ts = expr->ts;
1167627f7eb2Smrg block->ext.actual->expr->where = gfc_current_locus;
1168627f7eb2Smrg
1169627f7eb2Smrg /* C_F_POINTER's 2nd arg: ptr -- and its absent shape=. */
1170627f7eb2Smrg block->ext.actual->next = gfc_get_actual_arglist ();
1171627f7eb2Smrg block->ext.actual->next->expr = gfc_lval_expr_from_sym (ptr);
1172627f7eb2Smrg block->ext.actual->next->next = gfc_get_actual_arglist ();
1173627f7eb2Smrg
1174627f7eb2Smrg return block;
1175627f7eb2Smrg }
1176627f7eb2Smrg
1177627f7eb2Smrg
1178627f7eb2Smrg /* Calculates the offset to the (idx+1)th element of an array, taking the
1179627f7eb2Smrg stride into account. It generates the code:
1180627f7eb2Smrg offset = 0
1181627f7eb2Smrg do idx2 = 1, rank
1182627f7eb2Smrg offset = offset + mod (idx, sizes(idx2)) / sizes(idx2-1) * strides(idx2)
1183627f7eb2Smrg end do
1184627f7eb2Smrg offset = offset * byte_stride. */
1185627f7eb2Smrg
1186627f7eb2Smrg static gfc_code*
finalization_get_offset(gfc_symbol * idx,gfc_symbol * idx2,gfc_symbol * offset,gfc_symbol * strides,gfc_symbol * sizes,gfc_symbol * byte_stride,gfc_expr * rank,gfc_code * block,gfc_namespace * sub_ns)1187627f7eb2Smrg finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
1188627f7eb2Smrg gfc_symbol *strides, gfc_symbol *sizes,
1189627f7eb2Smrg gfc_symbol *byte_stride, gfc_expr *rank,
1190627f7eb2Smrg gfc_code *block, gfc_namespace *sub_ns)
1191627f7eb2Smrg {
1192627f7eb2Smrg gfc_iterator *iter;
1193627f7eb2Smrg gfc_expr *expr, *expr2;
1194627f7eb2Smrg
1195627f7eb2Smrg /* offset = 0. */
1196627f7eb2Smrg block->next = gfc_get_code (EXEC_ASSIGN);
1197627f7eb2Smrg block = block->next;
1198627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (offset);
1199627f7eb2Smrg block->expr2 = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1200627f7eb2Smrg
1201627f7eb2Smrg /* Create loop. */
1202627f7eb2Smrg iter = gfc_get_iterator ();
1203627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx2);
1204627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1205627f7eb2Smrg iter->end = gfc_copy_expr (rank);
1206627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1207627f7eb2Smrg block->next = gfc_get_code (EXEC_DO);
1208627f7eb2Smrg block = block->next;
1209627f7eb2Smrg block->ext.iterator = iter;
1210627f7eb2Smrg block->block = gfc_get_code (EXEC_DO);
1211627f7eb2Smrg
1212627f7eb2Smrg /* Loop body: offset = offset + mod (idx, sizes(idx2)) / sizes(idx2-1)
1213627f7eb2Smrg * strides(idx2). */
1214627f7eb2Smrg
1215627f7eb2Smrg /* mod (idx, sizes(idx2)). */
1216627f7eb2Smrg expr = gfc_lval_expr_from_sym (sizes);
1217627f7eb2Smrg expr->ref = gfc_get_ref ();
1218627f7eb2Smrg expr->ref->type = REF_ARRAY;
1219627f7eb2Smrg expr->ref->u.ar.as = sizes->as;
1220627f7eb2Smrg expr->ref->u.ar.type = AR_ELEMENT;
1221627f7eb2Smrg expr->ref->u.ar.dimen = 1;
1222627f7eb2Smrg expr->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1223627f7eb2Smrg expr->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx2);
1224627f7eb2Smrg expr->where = sizes->declared_at;
1225627f7eb2Smrg
1226627f7eb2Smrg expr = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_MOD, "mod",
1227627f7eb2Smrg gfc_current_locus, 2,
1228627f7eb2Smrg gfc_lval_expr_from_sym (idx), expr);
1229627f7eb2Smrg expr->ts = idx->ts;
1230627f7eb2Smrg
1231627f7eb2Smrg /* (...) / sizes(idx2-1). */
1232627f7eb2Smrg expr2 = gfc_get_expr ();
1233627f7eb2Smrg expr2->expr_type = EXPR_OP;
1234627f7eb2Smrg expr2->value.op.op = INTRINSIC_DIVIDE;
1235627f7eb2Smrg expr2->value.op.op1 = expr;
1236627f7eb2Smrg expr2->value.op.op2 = gfc_lval_expr_from_sym (sizes);
1237627f7eb2Smrg expr2->value.op.op2->ref = gfc_get_ref ();
1238627f7eb2Smrg expr2->value.op.op2->ref->type = REF_ARRAY;
1239627f7eb2Smrg expr2->value.op.op2->ref->u.ar.as = sizes->as;
1240627f7eb2Smrg expr2->value.op.op2->ref->u.ar.type = AR_ELEMENT;
1241627f7eb2Smrg expr2->value.op.op2->ref->u.ar.dimen = 1;
1242627f7eb2Smrg expr2->value.op.op2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1243627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0] = gfc_get_expr ();
1244627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->expr_type = EXPR_OP;
1245627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->where = gfc_current_locus;
1246627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
1247627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->value.op.op1
1248627f7eb2Smrg = gfc_lval_expr_from_sym (idx2);
1249627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->value.op.op2
1250627f7eb2Smrg = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1251627f7eb2Smrg expr2->value.op.op2->ref->u.ar.start[0]->ts
1252627f7eb2Smrg = expr2->value.op.op2->ref->u.ar.start[0]->value.op.op1->ts;
1253627f7eb2Smrg expr2->ts = idx->ts;
1254627f7eb2Smrg expr2->where = gfc_current_locus;
1255627f7eb2Smrg
1256627f7eb2Smrg /* ... * strides(idx2). */
1257627f7eb2Smrg expr = gfc_get_expr ();
1258627f7eb2Smrg expr->expr_type = EXPR_OP;
1259627f7eb2Smrg expr->value.op.op = INTRINSIC_TIMES;
1260627f7eb2Smrg expr->value.op.op1 = expr2;
1261627f7eb2Smrg expr->value.op.op2 = gfc_lval_expr_from_sym (strides);
1262627f7eb2Smrg expr->value.op.op2->ref = gfc_get_ref ();
1263627f7eb2Smrg expr->value.op.op2->ref->type = REF_ARRAY;
1264627f7eb2Smrg expr->value.op.op2->ref->u.ar.type = AR_ELEMENT;
1265627f7eb2Smrg expr->value.op.op2->ref->u.ar.dimen = 1;
1266627f7eb2Smrg expr->value.op.op2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1267627f7eb2Smrg expr->value.op.op2->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx2);
1268627f7eb2Smrg expr->value.op.op2->ref->u.ar.as = strides->as;
1269627f7eb2Smrg expr->ts = idx->ts;
1270627f7eb2Smrg expr->where = gfc_current_locus;
1271627f7eb2Smrg
1272627f7eb2Smrg /* offset = offset + ... */
1273627f7eb2Smrg block->block->next = gfc_get_code (EXEC_ASSIGN);
1274627f7eb2Smrg block->block->next->expr1 = gfc_lval_expr_from_sym (offset);
1275627f7eb2Smrg block->block->next->expr2 = gfc_get_expr ();
1276627f7eb2Smrg block->block->next->expr2->expr_type = EXPR_OP;
1277627f7eb2Smrg block->block->next->expr2->value.op.op = INTRINSIC_PLUS;
1278627f7eb2Smrg block->block->next->expr2->value.op.op1 = gfc_lval_expr_from_sym (offset);
1279627f7eb2Smrg block->block->next->expr2->value.op.op2 = expr;
1280627f7eb2Smrg block->block->next->expr2->ts = idx->ts;
1281627f7eb2Smrg block->block->next->expr2->where = gfc_current_locus;
1282627f7eb2Smrg
1283627f7eb2Smrg /* After the loop: offset = offset * byte_stride. */
1284627f7eb2Smrg block->next = gfc_get_code (EXEC_ASSIGN);
1285627f7eb2Smrg block = block->next;
1286627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (offset);
1287627f7eb2Smrg block->expr2 = gfc_get_expr ();
1288627f7eb2Smrg block->expr2->expr_type = EXPR_OP;
1289627f7eb2Smrg block->expr2->value.op.op = INTRINSIC_TIMES;
1290627f7eb2Smrg block->expr2->value.op.op1 = gfc_lval_expr_from_sym (offset);
1291627f7eb2Smrg block->expr2->value.op.op2 = gfc_lval_expr_from_sym (byte_stride);
1292627f7eb2Smrg block->expr2->ts = block->expr2->value.op.op1->ts;
1293627f7eb2Smrg block->expr2->where = gfc_current_locus;
1294627f7eb2Smrg return block;
1295627f7eb2Smrg }
1296627f7eb2Smrg
1297627f7eb2Smrg
1298627f7eb2Smrg /* Insert code of the following form:
1299627f7eb2Smrg
1300627f7eb2Smrg block
1301627f7eb2Smrg integer(c_intptr_t) :: i
1302627f7eb2Smrg
1303627f7eb2Smrg if ((byte_stride == STORAGE_SIZE (array)/NUMERIC_STORAGE_SIZE
1304627f7eb2Smrg && (is_contiguous || !final_rank3->attr.contiguous
1305627f7eb2Smrg || final_rank3->as->type != AS_ASSUMED_SHAPE))
1306627f7eb2Smrg || 0 == STORAGE_SIZE (array)) then
1307627f7eb2Smrg call final_rank3 (array)
1308627f7eb2Smrg else
1309627f7eb2Smrg block
1310627f7eb2Smrg integer(c_intptr_t) :: offset, j
1311627f7eb2Smrg type(t) :: tmp(shape (array))
1312627f7eb2Smrg
1313627f7eb2Smrg do i = 0, size (array)-1
1314627f7eb2Smrg offset = obtain_offset(i, strides, sizes, byte_stride)
1315627f7eb2Smrg addr = transfer (c_loc (array), addr) + offset
1316627f7eb2Smrg call c_f_pointer (transfer (addr, cptr), ptr)
1317627f7eb2Smrg
1318627f7eb2Smrg addr = transfer (c_loc (tmp), addr)
1319627f7eb2Smrg + i * STORAGE_SIZE (array)/NUMERIC_STORAGE_SIZE
1320627f7eb2Smrg call c_f_pointer (transfer (addr, cptr), ptr2)
1321627f7eb2Smrg ptr2 = ptr
1322627f7eb2Smrg end do
1323627f7eb2Smrg call final_rank3 (tmp)
1324627f7eb2Smrg end block
1325627f7eb2Smrg end if
1326627f7eb2Smrg block */
1327627f7eb2Smrg
1328627f7eb2Smrg static void
finalizer_insert_packed_call(gfc_code * block,gfc_finalizer * fini,gfc_symbol * array,gfc_symbol * byte_stride,gfc_symbol * idx,gfc_symbol * ptr,gfc_symbol * nelem,gfc_symbol * strides,gfc_symbol * sizes,gfc_symbol * idx2,gfc_symbol * offset,gfc_symbol * is_contiguous,gfc_expr * rank,gfc_namespace * sub_ns)1329627f7eb2Smrg finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
1330627f7eb2Smrg gfc_symbol *array, gfc_symbol *byte_stride,
1331627f7eb2Smrg gfc_symbol *idx, gfc_symbol *ptr,
1332627f7eb2Smrg gfc_symbol *nelem,
1333627f7eb2Smrg gfc_symbol *strides, gfc_symbol *sizes,
1334627f7eb2Smrg gfc_symbol *idx2, gfc_symbol *offset,
1335627f7eb2Smrg gfc_symbol *is_contiguous, gfc_expr *rank,
1336627f7eb2Smrg gfc_namespace *sub_ns)
1337627f7eb2Smrg {
1338627f7eb2Smrg gfc_symbol *tmp_array, *ptr2;
1339627f7eb2Smrg gfc_expr *size_expr, *offset2, *expr;
1340627f7eb2Smrg gfc_namespace *ns;
1341627f7eb2Smrg gfc_iterator *iter;
1342627f7eb2Smrg gfc_code *block2;
1343627f7eb2Smrg int i;
1344627f7eb2Smrg
1345627f7eb2Smrg block->next = gfc_get_code (EXEC_IF);
1346627f7eb2Smrg block = block->next;
1347627f7eb2Smrg
1348627f7eb2Smrg block->block = gfc_get_code (EXEC_IF);
1349627f7eb2Smrg block = block->block;
1350627f7eb2Smrg
1351627f7eb2Smrg /* size_expr = STORAGE_SIZE (...) / NUMERIC_STORAGE_SIZE. */
1352627f7eb2Smrg size_expr = gfc_get_expr ();
1353627f7eb2Smrg size_expr->where = gfc_current_locus;
1354627f7eb2Smrg size_expr->expr_type = EXPR_OP;
1355627f7eb2Smrg size_expr->value.op.op = INTRINSIC_DIVIDE;
1356627f7eb2Smrg
1357627f7eb2Smrg /* STORAGE_SIZE (array,kind=c_intptr_t). */
1358627f7eb2Smrg size_expr->value.op.op1
1359627f7eb2Smrg = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_STORAGE_SIZE,
1360627f7eb2Smrg "storage_size", gfc_current_locus, 2,
1361627f7eb2Smrg gfc_lval_expr_from_sym (array),
1362627f7eb2Smrg gfc_get_int_expr (gfc_index_integer_kind,
1363627f7eb2Smrg NULL, 0));
1364627f7eb2Smrg
1365627f7eb2Smrg /* NUMERIC_STORAGE_SIZE. */
1366627f7eb2Smrg size_expr->value.op.op2 = gfc_get_int_expr (gfc_index_integer_kind, NULL,
1367627f7eb2Smrg gfc_character_storage_size);
1368627f7eb2Smrg size_expr->value.op.op1->ts = size_expr->value.op.op2->ts;
1369627f7eb2Smrg size_expr->ts = size_expr->value.op.op1->ts;
1370627f7eb2Smrg
1371627f7eb2Smrg /* IF condition: (stride == size_expr
1372627f7eb2Smrg && ((fini's as->ASSUMED_SIZE && !fini's attr.contiguous)
1373627f7eb2Smrg || is_contiguous)
1374627f7eb2Smrg || 0 == size_expr. */
1375627f7eb2Smrg block->expr1 = gfc_get_expr ();
1376627f7eb2Smrg block->expr1->ts.type = BT_LOGICAL;
1377627f7eb2Smrg block->expr1->ts.kind = gfc_default_logical_kind;
1378627f7eb2Smrg block->expr1->expr_type = EXPR_OP;
1379627f7eb2Smrg block->expr1->where = gfc_current_locus;
1380627f7eb2Smrg
1381627f7eb2Smrg block->expr1->value.op.op = INTRINSIC_OR;
1382627f7eb2Smrg
1383627f7eb2Smrg /* byte_stride == size_expr */
1384627f7eb2Smrg expr = gfc_get_expr ();
1385627f7eb2Smrg expr->ts.type = BT_LOGICAL;
1386627f7eb2Smrg expr->ts.kind = gfc_default_logical_kind;
1387627f7eb2Smrg expr->expr_type = EXPR_OP;
1388627f7eb2Smrg expr->where = gfc_current_locus;
1389627f7eb2Smrg expr->value.op.op = INTRINSIC_EQ;
1390627f7eb2Smrg expr->value.op.op1
1391627f7eb2Smrg = gfc_lval_expr_from_sym (byte_stride);
1392627f7eb2Smrg expr->value.op.op2 = size_expr;
1393627f7eb2Smrg
1394627f7eb2Smrg /* If strides aren't allowed (not assumed shape or CONTIGUOUS),
1395627f7eb2Smrg add is_contiguous check. */
1396627f7eb2Smrg
1397627f7eb2Smrg if (fini->proc_tree->n.sym->formal->sym->as->type != AS_ASSUMED_SHAPE
1398627f7eb2Smrg || fini->proc_tree->n.sym->formal->sym->attr.contiguous)
1399627f7eb2Smrg {
1400627f7eb2Smrg gfc_expr *expr2;
1401627f7eb2Smrg expr2 = gfc_get_expr ();
1402627f7eb2Smrg expr2->ts.type = BT_LOGICAL;
1403627f7eb2Smrg expr2->ts.kind = gfc_default_logical_kind;
1404627f7eb2Smrg expr2->expr_type = EXPR_OP;
1405627f7eb2Smrg expr2->where = gfc_current_locus;
1406627f7eb2Smrg expr2->value.op.op = INTRINSIC_AND;
1407627f7eb2Smrg expr2->value.op.op1 = expr;
1408627f7eb2Smrg expr2->value.op.op2 = gfc_lval_expr_from_sym (is_contiguous);
1409627f7eb2Smrg expr = expr2;
1410627f7eb2Smrg }
1411627f7eb2Smrg
1412627f7eb2Smrg block->expr1->value.op.op1 = expr;
1413627f7eb2Smrg
1414627f7eb2Smrg /* 0 == size_expr */
1415627f7eb2Smrg block->expr1->value.op.op2 = gfc_get_expr ();
1416627f7eb2Smrg block->expr1->value.op.op2->ts.type = BT_LOGICAL;
1417627f7eb2Smrg block->expr1->value.op.op2->ts.kind = gfc_default_logical_kind;
1418627f7eb2Smrg block->expr1->value.op.op2->expr_type = EXPR_OP;
1419627f7eb2Smrg block->expr1->value.op.op2->where = gfc_current_locus;
1420627f7eb2Smrg block->expr1->value.op.op2->value.op.op = INTRINSIC_EQ;
1421627f7eb2Smrg block->expr1->value.op.op2->value.op.op1 =
1422627f7eb2Smrg gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1423627f7eb2Smrg block->expr1->value.op.op2->value.op.op2 = gfc_copy_expr (size_expr);
1424627f7eb2Smrg
1425627f7eb2Smrg /* IF body: call final subroutine. */
1426627f7eb2Smrg block->next = gfc_get_code (EXEC_CALL);
1427627f7eb2Smrg block->next->symtree = fini->proc_tree;
1428627f7eb2Smrg block->next->resolved_sym = fini->proc_tree->n.sym;
1429627f7eb2Smrg block->next->ext.actual = gfc_get_actual_arglist ();
1430627f7eb2Smrg block->next->ext.actual->expr = gfc_lval_expr_from_sym (array);
1431627f7eb2Smrg block->next->ext.actual->next = gfc_get_actual_arglist ();
1432627f7eb2Smrg block->next->ext.actual->next->expr = gfc_copy_expr (size_expr);
1433627f7eb2Smrg
1434627f7eb2Smrg /* ELSE. */
1435627f7eb2Smrg
1436627f7eb2Smrg block->block = gfc_get_code (EXEC_IF);
1437627f7eb2Smrg block = block->block;
1438627f7eb2Smrg
1439627f7eb2Smrg /* BLOCK ... END BLOCK. */
1440627f7eb2Smrg block->next = gfc_get_code (EXEC_BLOCK);
1441627f7eb2Smrg block = block->next;
1442627f7eb2Smrg
1443627f7eb2Smrg ns = gfc_build_block_ns (sub_ns);
1444627f7eb2Smrg block->ext.block.ns = ns;
1445627f7eb2Smrg block->ext.block.assoc = NULL;
1446627f7eb2Smrg
1447627f7eb2Smrg gfc_get_symbol ("ptr2", ns, &ptr2);
1448627f7eb2Smrg ptr2->ts.type = BT_DERIVED;
1449627f7eb2Smrg ptr2->ts.u.derived = array->ts.u.derived;
1450627f7eb2Smrg ptr2->attr.flavor = FL_VARIABLE;
1451627f7eb2Smrg ptr2->attr.pointer = 1;
1452627f7eb2Smrg ptr2->attr.artificial = 1;
1453627f7eb2Smrg gfc_set_sym_referenced (ptr2);
1454627f7eb2Smrg gfc_commit_symbol (ptr2);
1455627f7eb2Smrg
1456627f7eb2Smrg gfc_get_symbol ("tmp_array", ns, &tmp_array);
1457627f7eb2Smrg tmp_array->ts.type = BT_DERIVED;
1458627f7eb2Smrg tmp_array->ts.u.derived = array->ts.u.derived;
1459627f7eb2Smrg tmp_array->attr.flavor = FL_VARIABLE;
1460627f7eb2Smrg tmp_array->attr.dimension = 1;
1461627f7eb2Smrg tmp_array->attr.artificial = 1;
1462627f7eb2Smrg tmp_array->as = gfc_get_array_spec();
1463627f7eb2Smrg tmp_array->attr.intent = INTENT_INOUT;
1464627f7eb2Smrg tmp_array->as->type = AS_EXPLICIT;
1465627f7eb2Smrg tmp_array->as->rank = fini->proc_tree->n.sym->formal->sym->as->rank;
1466627f7eb2Smrg
1467627f7eb2Smrg for (i = 0; i < tmp_array->as->rank; i++)
1468627f7eb2Smrg {
1469627f7eb2Smrg gfc_expr *shape_expr;
1470627f7eb2Smrg tmp_array->as->lower[i] = gfc_get_int_expr (gfc_default_integer_kind,
1471627f7eb2Smrg NULL, 1);
1472627f7eb2Smrg /* SIZE (array, dim=i+1, kind=gfc_index_integer_kind). */
1473627f7eb2Smrg shape_expr
1474627f7eb2Smrg = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_SIZE, "size",
1475627f7eb2Smrg gfc_current_locus, 3,
1476627f7eb2Smrg gfc_lval_expr_from_sym (array),
1477627f7eb2Smrg gfc_get_int_expr (gfc_default_integer_kind,
1478627f7eb2Smrg NULL, i+1),
1479627f7eb2Smrg gfc_get_int_expr (gfc_default_integer_kind,
1480627f7eb2Smrg NULL,
1481627f7eb2Smrg gfc_index_integer_kind));
1482627f7eb2Smrg shape_expr->ts.kind = gfc_index_integer_kind;
1483627f7eb2Smrg tmp_array->as->upper[i] = shape_expr;
1484627f7eb2Smrg }
1485627f7eb2Smrg gfc_set_sym_referenced (tmp_array);
1486627f7eb2Smrg gfc_commit_symbol (tmp_array);
1487627f7eb2Smrg
1488627f7eb2Smrg /* Create loop. */
1489627f7eb2Smrg iter = gfc_get_iterator ();
1490627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx);
1491627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1492627f7eb2Smrg iter->end = gfc_lval_expr_from_sym (nelem);
1493627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1494627f7eb2Smrg
1495627f7eb2Smrg block = gfc_get_code (EXEC_DO);
1496627f7eb2Smrg ns->code = block;
1497627f7eb2Smrg block->ext.iterator = iter;
1498627f7eb2Smrg block->block = gfc_get_code (EXEC_DO);
1499627f7eb2Smrg
1500627f7eb2Smrg /* Offset calculation for the new array: idx * size of type (in bytes). */
1501627f7eb2Smrg offset2 = gfc_get_expr ();
1502627f7eb2Smrg offset2->expr_type = EXPR_OP;
1503627f7eb2Smrg offset2->where = gfc_current_locus;
1504627f7eb2Smrg offset2->value.op.op = INTRINSIC_TIMES;
1505627f7eb2Smrg offset2->value.op.op1 = gfc_lval_expr_from_sym (idx);
1506627f7eb2Smrg offset2->value.op.op2 = gfc_copy_expr (size_expr);
1507627f7eb2Smrg offset2->ts = byte_stride->ts;
1508627f7eb2Smrg
1509627f7eb2Smrg /* Offset calculation of "array". */
1510627f7eb2Smrg block2 = finalization_get_offset (idx, idx2, offset, strides, sizes,
1511627f7eb2Smrg byte_stride, rank, block->block, sub_ns);
1512627f7eb2Smrg
1513627f7eb2Smrg /* Create code for
1514627f7eb2Smrg CALL C_F_POINTER (TRANSFER (TRANSFER (C_LOC (array, cptr), c_intptr)
1515627f7eb2Smrg + idx * stride, c_ptr), ptr). */
1516627f7eb2Smrg block2->next = finalization_scalarizer (array, ptr,
1517627f7eb2Smrg gfc_lval_expr_from_sym (offset),
1518627f7eb2Smrg sub_ns);
1519627f7eb2Smrg block2 = block2->next;
1520627f7eb2Smrg block2->next = finalization_scalarizer (tmp_array, ptr2, offset2, sub_ns);
1521627f7eb2Smrg block2 = block2->next;
1522627f7eb2Smrg
1523627f7eb2Smrg /* ptr2 = ptr. */
1524627f7eb2Smrg block2->next = gfc_get_code (EXEC_ASSIGN);
1525627f7eb2Smrg block2 = block2->next;
1526627f7eb2Smrg block2->expr1 = gfc_lval_expr_from_sym (ptr2);
1527627f7eb2Smrg block2->expr2 = gfc_lval_expr_from_sym (ptr);
1528627f7eb2Smrg
1529627f7eb2Smrg /* Call now the user's final subroutine. */
1530627f7eb2Smrg block->next = gfc_get_code (EXEC_CALL);
1531627f7eb2Smrg block = block->next;
1532627f7eb2Smrg block->symtree = fini->proc_tree;
1533627f7eb2Smrg block->resolved_sym = fini->proc_tree->n.sym;
1534627f7eb2Smrg block->ext.actual = gfc_get_actual_arglist ();
1535627f7eb2Smrg block->ext.actual->expr = gfc_lval_expr_from_sym (tmp_array);
1536627f7eb2Smrg
1537627f7eb2Smrg if (fini->proc_tree->n.sym->formal->sym->attr.intent == INTENT_IN)
1538627f7eb2Smrg return;
1539627f7eb2Smrg
1540627f7eb2Smrg /* Copy back. */
1541627f7eb2Smrg
1542627f7eb2Smrg /* Loop. */
1543627f7eb2Smrg iter = gfc_get_iterator ();
1544627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx);
1545627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1546627f7eb2Smrg iter->end = gfc_lval_expr_from_sym (nelem);
1547627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1548627f7eb2Smrg
1549627f7eb2Smrg block->next = gfc_get_code (EXEC_DO);
1550627f7eb2Smrg block = block->next;
1551627f7eb2Smrg block->ext.iterator = iter;
1552627f7eb2Smrg block->block = gfc_get_code (EXEC_DO);
1553627f7eb2Smrg
1554627f7eb2Smrg /* Offset calculation of "array". */
1555627f7eb2Smrg block2 = finalization_get_offset (idx, idx2, offset, strides, sizes,
1556627f7eb2Smrg byte_stride, rank, block->block, sub_ns);
1557627f7eb2Smrg
1558627f7eb2Smrg /* Create code for
1559627f7eb2Smrg CALL C_F_POINTER (TRANSFER (TRANSFER (C_LOC (array, cptr), c_intptr)
1560627f7eb2Smrg + offset, c_ptr), ptr). */
1561627f7eb2Smrg block2->next = finalization_scalarizer (array, ptr,
1562627f7eb2Smrg gfc_lval_expr_from_sym (offset),
1563627f7eb2Smrg sub_ns);
1564627f7eb2Smrg block2 = block2->next;
1565627f7eb2Smrg block2->next = finalization_scalarizer (tmp_array, ptr2,
1566627f7eb2Smrg gfc_copy_expr (offset2), sub_ns);
1567627f7eb2Smrg block2 = block2->next;
1568627f7eb2Smrg
1569627f7eb2Smrg /* ptr = ptr2. */
1570627f7eb2Smrg block2->next = gfc_get_code (EXEC_ASSIGN);
1571627f7eb2Smrg block2->next->expr1 = gfc_lval_expr_from_sym (ptr);
1572627f7eb2Smrg block2->next->expr2 = gfc_lval_expr_from_sym (ptr2);
1573627f7eb2Smrg }
1574627f7eb2Smrg
1575627f7eb2Smrg
1576627f7eb2Smrg /* Generate the finalization/polymorphic freeing wrapper subroutine for the
1577627f7eb2Smrg derived type "derived". The function first calls the approriate FINAL
1578627f7eb2Smrg subroutine, then it DEALLOCATEs (finalizes/frees) the allocatable
1579627f7eb2Smrg components (but not the inherited ones). Last, it calls the wrapper
1580627f7eb2Smrg subroutine of the parent. The generated wrapper procedure takes as argument
1581627f7eb2Smrg an assumed-rank array.
1582627f7eb2Smrg If neither allocatable components nor FINAL subroutines exists, the vtab
1583627f7eb2Smrg will contain a NULL pointer.
1584627f7eb2Smrg The generated function has the form
1585627f7eb2Smrg _final(assumed-rank array, stride, skip_corarray)
1586627f7eb2Smrg where the array has to be contiguous (except of the lowest dimension). The
1587627f7eb2Smrg stride (in bytes) is used to allow different sizes for ancestor types by
1588627f7eb2Smrg skipping over the additionally added components in the scalarizer. If
1589627f7eb2Smrg "fini_coarray" is false, coarray components are not finalized to allow for
1590627f7eb2Smrg the correct semantic with intrinsic assignment. */
1591627f7eb2Smrg
1592627f7eb2Smrg static void
generate_finalization_wrapper(gfc_symbol * derived,gfc_namespace * ns,const char * tname,gfc_component * vtab_final)1593627f7eb2Smrg generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
1594627f7eb2Smrg const char *tname, gfc_component *vtab_final)
1595627f7eb2Smrg {
1596627f7eb2Smrg gfc_symbol *final, *array, *fini_coarray, *byte_stride, *sizes, *strides;
1597627f7eb2Smrg gfc_symbol *ptr = NULL, *idx, *idx2, *is_contiguous, *offset, *nelem;
1598627f7eb2Smrg gfc_component *comp;
1599627f7eb2Smrg gfc_namespace *sub_ns;
1600627f7eb2Smrg gfc_code *last_code, *block;
1601627f7eb2Smrg char *name;
1602627f7eb2Smrg bool finalizable_comp = false;
1603627f7eb2Smrg bool expr_null_wrapper = false;
1604627f7eb2Smrg gfc_expr *ancestor_wrapper = NULL, *rank;
1605627f7eb2Smrg gfc_iterator *iter;
1606627f7eb2Smrg
1607627f7eb2Smrg if (derived->attr.unlimited_polymorphic)
1608627f7eb2Smrg {
1609627f7eb2Smrg vtab_final->initializer = gfc_get_null_expr (NULL);
1610627f7eb2Smrg return;
1611627f7eb2Smrg }
1612627f7eb2Smrg
1613627f7eb2Smrg /* Search for the ancestor's finalizers. */
1614627f7eb2Smrg if (derived->attr.extension && derived->components
1615627f7eb2Smrg && (!derived->components->ts.u.derived->attr.abstract
1616627f7eb2Smrg || has_finalizer_component (derived)))
1617627f7eb2Smrg {
1618627f7eb2Smrg gfc_symbol *vtab;
1619627f7eb2Smrg gfc_component *comp;
1620627f7eb2Smrg
1621627f7eb2Smrg vtab = gfc_find_derived_vtab (derived->components->ts.u.derived);
1622627f7eb2Smrg for (comp = vtab->ts.u.derived->components; comp; comp = comp->next)
1623627f7eb2Smrg if (comp->name[0] == '_' && comp->name[1] == 'f')
1624627f7eb2Smrg {
1625627f7eb2Smrg ancestor_wrapper = comp->initializer;
1626627f7eb2Smrg break;
1627627f7eb2Smrg }
1628627f7eb2Smrg }
1629627f7eb2Smrg
1630627f7eb2Smrg /* No wrapper of the ancestor and no own FINAL subroutines and allocatable
1631*4c3eb207Smrg components: Return a NULL() expression; we defer this a bit to have
1632627f7eb2Smrg an interface declaration. */
1633627f7eb2Smrg if ((!ancestor_wrapper || ancestor_wrapper->expr_type == EXPR_NULL)
1634627f7eb2Smrg && !derived->attr.alloc_comp
1635627f7eb2Smrg && (!derived->f2k_derived || !derived->f2k_derived->finalizers)
1636627f7eb2Smrg && !has_finalizer_component (derived))
1637627f7eb2Smrg expr_null_wrapper = true;
1638627f7eb2Smrg else
1639627f7eb2Smrg /* Check whether there are new allocatable components. */
1640627f7eb2Smrg for (comp = derived->components; comp; comp = comp->next)
1641627f7eb2Smrg {
1642627f7eb2Smrg if (comp == derived->components && derived->attr.extension
1643627f7eb2Smrg && ancestor_wrapper && ancestor_wrapper->expr_type != EXPR_NULL)
1644627f7eb2Smrg continue;
1645627f7eb2Smrg
1646627f7eb2Smrg finalizable_comp |= comp_is_finalizable (comp);
1647627f7eb2Smrg }
1648627f7eb2Smrg
1649627f7eb2Smrg /* If there is no new finalizer and no new allocatable, return with
1650627f7eb2Smrg an expr to the ancestor's one. */
1651627f7eb2Smrg if (!expr_null_wrapper && !finalizable_comp
1652627f7eb2Smrg && (!derived->f2k_derived || !derived->f2k_derived->finalizers))
1653627f7eb2Smrg {
1654627f7eb2Smrg gcc_assert (ancestor_wrapper && ancestor_wrapper->ref == NULL
1655627f7eb2Smrg && ancestor_wrapper->expr_type == EXPR_VARIABLE);
1656627f7eb2Smrg vtab_final->initializer = gfc_copy_expr (ancestor_wrapper);
1657627f7eb2Smrg vtab_final->ts.interface = vtab_final->initializer->symtree->n.sym;
1658627f7eb2Smrg return;
1659627f7eb2Smrg }
1660627f7eb2Smrg
1661627f7eb2Smrg /* We now create a wrapper, which does the following:
1662627f7eb2Smrg 1. Call the suitable finalization subroutine for this type
1663627f7eb2Smrg 2. Loop over all noninherited allocatable components and noninherited
1664627f7eb2Smrg components with allocatable components and DEALLOCATE those; this will
1665627f7eb2Smrg take care of finalizers, coarray deregistering and allocatable
1666627f7eb2Smrg nested components.
1667627f7eb2Smrg 3. Call the ancestor's finalizer. */
1668627f7eb2Smrg
1669627f7eb2Smrg /* Declare the wrapper function; it takes an assumed-rank array
1670627f7eb2Smrg and a VALUE logical as arguments. */
1671627f7eb2Smrg
1672627f7eb2Smrg /* Set up the namespace. */
1673627f7eb2Smrg sub_ns = gfc_get_namespace (ns, 0);
1674627f7eb2Smrg sub_ns->sibling = ns->contained;
1675627f7eb2Smrg if (!expr_null_wrapper)
1676627f7eb2Smrg ns->contained = sub_ns;
1677627f7eb2Smrg sub_ns->resolved = 1;
1678627f7eb2Smrg
1679627f7eb2Smrg /* Set up the procedure symbol. */
1680627f7eb2Smrg name = xasprintf ("__final_%s", tname);
1681627f7eb2Smrg gfc_get_symbol (name, sub_ns, &final);
1682627f7eb2Smrg sub_ns->proc_name = final;
1683627f7eb2Smrg final->attr.flavor = FL_PROCEDURE;
1684627f7eb2Smrg final->attr.function = 1;
1685627f7eb2Smrg final->attr.pure = 0;
1686627f7eb2Smrg final->attr.recursive = 1;
1687627f7eb2Smrg final->result = final;
1688627f7eb2Smrg final->ts.type = BT_INTEGER;
1689627f7eb2Smrg final->ts.kind = 4;
1690627f7eb2Smrg final->attr.artificial = 1;
1691627f7eb2Smrg final->attr.always_explicit = 1;
1692627f7eb2Smrg final->attr.if_source = expr_null_wrapper ? IFSRC_IFBODY : IFSRC_DECL;
1693627f7eb2Smrg if (ns->proc_name->attr.flavor == FL_MODULE)
1694627f7eb2Smrg final->module = ns->proc_name->name;
1695627f7eb2Smrg gfc_set_sym_referenced (final);
1696627f7eb2Smrg gfc_commit_symbol (final);
1697627f7eb2Smrg
1698627f7eb2Smrg /* Set up formal argument. */
1699627f7eb2Smrg gfc_get_symbol ("array", sub_ns, &array);
1700627f7eb2Smrg array->ts.type = BT_DERIVED;
1701627f7eb2Smrg array->ts.u.derived = derived;
1702627f7eb2Smrg array->attr.flavor = FL_VARIABLE;
1703627f7eb2Smrg array->attr.dummy = 1;
1704627f7eb2Smrg array->attr.contiguous = 1;
1705627f7eb2Smrg array->attr.dimension = 1;
1706627f7eb2Smrg array->attr.artificial = 1;
1707627f7eb2Smrg array->as = gfc_get_array_spec();
1708627f7eb2Smrg array->as->type = AS_ASSUMED_RANK;
1709627f7eb2Smrg array->as->rank = -1;
1710627f7eb2Smrg array->attr.intent = INTENT_INOUT;
1711627f7eb2Smrg gfc_set_sym_referenced (array);
1712627f7eb2Smrg final->formal = gfc_get_formal_arglist ();
1713627f7eb2Smrg final->formal->sym = array;
1714627f7eb2Smrg gfc_commit_symbol (array);
1715627f7eb2Smrg
1716627f7eb2Smrg /* Set up formal argument. */
1717627f7eb2Smrg gfc_get_symbol ("byte_stride", sub_ns, &byte_stride);
1718627f7eb2Smrg byte_stride->ts.type = BT_INTEGER;
1719627f7eb2Smrg byte_stride->ts.kind = gfc_index_integer_kind;
1720627f7eb2Smrg byte_stride->attr.flavor = FL_VARIABLE;
1721627f7eb2Smrg byte_stride->attr.dummy = 1;
1722627f7eb2Smrg byte_stride->attr.value = 1;
1723627f7eb2Smrg byte_stride->attr.artificial = 1;
1724627f7eb2Smrg gfc_set_sym_referenced (byte_stride);
1725627f7eb2Smrg final->formal->next = gfc_get_formal_arglist ();
1726627f7eb2Smrg final->formal->next->sym = byte_stride;
1727627f7eb2Smrg gfc_commit_symbol (byte_stride);
1728627f7eb2Smrg
1729627f7eb2Smrg /* Set up formal argument. */
1730627f7eb2Smrg gfc_get_symbol ("fini_coarray", sub_ns, &fini_coarray);
1731627f7eb2Smrg fini_coarray->ts.type = BT_LOGICAL;
1732627f7eb2Smrg fini_coarray->ts.kind = 1;
1733627f7eb2Smrg fini_coarray->attr.flavor = FL_VARIABLE;
1734627f7eb2Smrg fini_coarray->attr.dummy = 1;
1735627f7eb2Smrg fini_coarray->attr.value = 1;
1736627f7eb2Smrg fini_coarray->attr.artificial = 1;
1737627f7eb2Smrg gfc_set_sym_referenced (fini_coarray);
1738627f7eb2Smrg final->formal->next->next = gfc_get_formal_arglist ();
1739627f7eb2Smrg final->formal->next->next->sym = fini_coarray;
1740627f7eb2Smrg gfc_commit_symbol (fini_coarray);
1741627f7eb2Smrg
1742627f7eb2Smrg /* Return with a NULL() expression but with an interface which has
1743627f7eb2Smrg the formal arguments. */
1744627f7eb2Smrg if (expr_null_wrapper)
1745627f7eb2Smrg {
1746627f7eb2Smrg vtab_final->initializer = gfc_get_null_expr (NULL);
1747627f7eb2Smrg vtab_final->ts.interface = final;
1748627f7eb2Smrg return;
1749627f7eb2Smrg }
1750627f7eb2Smrg
1751627f7eb2Smrg /* Local variables. */
1752627f7eb2Smrg
1753627f7eb2Smrg gfc_get_symbol ("idx", sub_ns, &idx);
1754627f7eb2Smrg idx->ts.type = BT_INTEGER;
1755627f7eb2Smrg idx->ts.kind = gfc_index_integer_kind;
1756627f7eb2Smrg idx->attr.flavor = FL_VARIABLE;
1757627f7eb2Smrg idx->attr.artificial = 1;
1758627f7eb2Smrg gfc_set_sym_referenced (idx);
1759627f7eb2Smrg gfc_commit_symbol (idx);
1760627f7eb2Smrg
1761627f7eb2Smrg gfc_get_symbol ("idx2", sub_ns, &idx2);
1762627f7eb2Smrg idx2->ts.type = BT_INTEGER;
1763627f7eb2Smrg idx2->ts.kind = gfc_index_integer_kind;
1764627f7eb2Smrg idx2->attr.flavor = FL_VARIABLE;
1765627f7eb2Smrg idx2->attr.artificial = 1;
1766627f7eb2Smrg gfc_set_sym_referenced (idx2);
1767627f7eb2Smrg gfc_commit_symbol (idx2);
1768627f7eb2Smrg
1769627f7eb2Smrg gfc_get_symbol ("offset", sub_ns, &offset);
1770627f7eb2Smrg offset->ts.type = BT_INTEGER;
1771627f7eb2Smrg offset->ts.kind = gfc_index_integer_kind;
1772627f7eb2Smrg offset->attr.flavor = FL_VARIABLE;
1773627f7eb2Smrg offset->attr.artificial = 1;
1774627f7eb2Smrg gfc_set_sym_referenced (offset);
1775627f7eb2Smrg gfc_commit_symbol (offset);
1776627f7eb2Smrg
1777627f7eb2Smrg /* Create RANK expression. */
1778627f7eb2Smrg rank = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_RANK, "rank",
1779627f7eb2Smrg gfc_current_locus, 1,
1780627f7eb2Smrg gfc_lval_expr_from_sym (array));
1781627f7eb2Smrg if (rank->ts.kind != idx->ts.kind)
1782627f7eb2Smrg gfc_convert_type_warn (rank, &idx->ts, 2, 0);
1783627f7eb2Smrg
1784627f7eb2Smrg /* Create is_contiguous variable. */
1785627f7eb2Smrg gfc_get_symbol ("is_contiguous", sub_ns, &is_contiguous);
1786627f7eb2Smrg is_contiguous->ts.type = BT_LOGICAL;
1787627f7eb2Smrg is_contiguous->ts.kind = gfc_default_logical_kind;
1788627f7eb2Smrg is_contiguous->attr.flavor = FL_VARIABLE;
1789627f7eb2Smrg is_contiguous->attr.artificial = 1;
1790627f7eb2Smrg gfc_set_sym_referenced (is_contiguous);
1791627f7eb2Smrg gfc_commit_symbol (is_contiguous);
1792627f7eb2Smrg
1793627f7eb2Smrg /* Create "sizes(0..rank)" variable, which contains the multiplied
1794627f7eb2Smrg up extent of the dimensions, i.e. sizes(0) = 1, sizes(1) = extent(dim=1),
1795627f7eb2Smrg sizes(2) = sizes(1) * extent(dim=2) etc. */
1796627f7eb2Smrg gfc_get_symbol ("sizes", sub_ns, &sizes);
1797627f7eb2Smrg sizes->ts.type = BT_INTEGER;
1798627f7eb2Smrg sizes->ts.kind = gfc_index_integer_kind;
1799627f7eb2Smrg sizes->attr.flavor = FL_VARIABLE;
1800627f7eb2Smrg sizes->attr.dimension = 1;
1801627f7eb2Smrg sizes->attr.artificial = 1;
1802627f7eb2Smrg sizes->as = gfc_get_array_spec();
1803627f7eb2Smrg sizes->attr.intent = INTENT_INOUT;
1804627f7eb2Smrg sizes->as->type = AS_EXPLICIT;
1805627f7eb2Smrg sizes->as->rank = 1;
1806627f7eb2Smrg sizes->as->lower[0] = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1807627f7eb2Smrg sizes->as->upper[0] = gfc_copy_expr (rank);
1808627f7eb2Smrg gfc_set_sym_referenced (sizes);
1809627f7eb2Smrg gfc_commit_symbol (sizes);
1810627f7eb2Smrg
1811627f7eb2Smrg /* Create "strides(1..rank)" variable, which contains the strides per
1812627f7eb2Smrg dimension. */
1813627f7eb2Smrg gfc_get_symbol ("strides", sub_ns, &strides);
1814627f7eb2Smrg strides->ts.type = BT_INTEGER;
1815627f7eb2Smrg strides->ts.kind = gfc_index_integer_kind;
1816627f7eb2Smrg strides->attr.flavor = FL_VARIABLE;
1817627f7eb2Smrg strides->attr.dimension = 1;
1818627f7eb2Smrg strides->attr.artificial = 1;
1819627f7eb2Smrg strides->as = gfc_get_array_spec();
1820627f7eb2Smrg strides->attr.intent = INTENT_INOUT;
1821627f7eb2Smrg strides->as->type = AS_EXPLICIT;
1822627f7eb2Smrg strides->as->rank = 1;
1823627f7eb2Smrg strides->as->lower[0] = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1824627f7eb2Smrg strides->as->upper[0] = gfc_copy_expr (rank);
1825627f7eb2Smrg gfc_set_sym_referenced (strides);
1826627f7eb2Smrg gfc_commit_symbol (strides);
1827627f7eb2Smrg
1828627f7eb2Smrg
1829627f7eb2Smrg /* Set return value to 0. */
1830627f7eb2Smrg last_code = gfc_get_code (EXEC_ASSIGN);
1831627f7eb2Smrg last_code->expr1 = gfc_lval_expr_from_sym (final);
1832627f7eb2Smrg last_code->expr2 = gfc_get_int_expr (4, NULL, 0);
1833627f7eb2Smrg sub_ns->code = last_code;
1834627f7eb2Smrg
1835627f7eb2Smrg /* Set: is_contiguous = .true. */
1836627f7eb2Smrg last_code->next = gfc_get_code (EXEC_ASSIGN);
1837627f7eb2Smrg last_code = last_code->next;
1838627f7eb2Smrg last_code->expr1 = gfc_lval_expr_from_sym (is_contiguous);
1839627f7eb2Smrg last_code->expr2 = gfc_get_logical_expr (gfc_default_logical_kind,
1840627f7eb2Smrg &gfc_current_locus, true);
1841627f7eb2Smrg
1842627f7eb2Smrg /* Set: sizes(0) = 1. */
1843627f7eb2Smrg last_code->next = gfc_get_code (EXEC_ASSIGN);
1844627f7eb2Smrg last_code = last_code->next;
1845627f7eb2Smrg last_code->expr1 = gfc_lval_expr_from_sym (sizes);
1846627f7eb2Smrg last_code->expr1->ref = gfc_get_ref ();
1847627f7eb2Smrg last_code->expr1->ref->type = REF_ARRAY;
1848627f7eb2Smrg last_code->expr1->ref->u.ar.type = AR_ELEMENT;
1849627f7eb2Smrg last_code->expr1->ref->u.ar.dimen = 1;
1850627f7eb2Smrg last_code->expr1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1851627f7eb2Smrg last_code->expr1->ref->u.ar.start[0]
1852627f7eb2Smrg = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
1853627f7eb2Smrg last_code->expr1->ref->u.ar.as = sizes->as;
1854627f7eb2Smrg last_code->expr2 = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1);
1855627f7eb2Smrg
1856627f7eb2Smrg /* Create:
1857627f7eb2Smrg DO idx = 1, rank
1858627f7eb2Smrg strides(idx) = _F._stride (array, dim=idx)
1859627f7eb2Smrg sizes(idx) = sizes(i-1) * size(array, dim=idx, kind=index_kind)
1860627f7eb2Smrg if (strides (idx) /= sizes(i-1)) is_contiguous = .false.
1861627f7eb2Smrg END DO. */
1862627f7eb2Smrg
1863627f7eb2Smrg /* Create loop. */
1864627f7eb2Smrg iter = gfc_get_iterator ();
1865627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx);
1866627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1867627f7eb2Smrg iter->end = gfc_copy_expr (rank);
1868627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1869627f7eb2Smrg last_code->next = gfc_get_code (EXEC_DO);
1870627f7eb2Smrg last_code = last_code->next;
1871627f7eb2Smrg last_code->ext.iterator = iter;
1872627f7eb2Smrg last_code->block = gfc_get_code (EXEC_DO);
1873627f7eb2Smrg
1874627f7eb2Smrg /* strides(idx) = _F._stride(array,dim=idx). */
1875627f7eb2Smrg last_code->block->next = gfc_get_code (EXEC_ASSIGN);
1876627f7eb2Smrg block = last_code->block->next;
1877627f7eb2Smrg
1878627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (strides);
1879627f7eb2Smrg block->expr1->ref = gfc_get_ref ();
1880627f7eb2Smrg block->expr1->ref->type = REF_ARRAY;
1881627f7eb2Smrg block->expr1->ref->u.ar.type = AR_ELEMENT;
1882627f7eb2Smrg block->expr1->ref->u.ar.dimen = 1;
1883627f7eb2Smrg block->expr1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1884627f7eb2Smrg block->expr1->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx);
1885627f7eb2Smrg block->expr1->ref->u.ar.as = strides->as;
1886627f7eb2Smrg
1887627f7eb2Smrg block->expr2 = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_STRIDE, "stride",
1888627f7eb2Smrg gfc_current_locus, 2,
1889627f7eb2Smrg gfc_lval_expr_from_sym (array),
1890627f7eb2Smrg gfc_lval_expr_from_sym (idx));
1891627f7eb2Smrg
1892627f7eb2Smrg /* sizes(idx) = sizes(idx-1) * size(array,dim=idx, kind=index_kind). */
1893627f7eb2Smrg block->next = gfc_get_code (EXEC_ASSIGN);
1894627f7eb2Smrg block = block->next;
1895627f7eb2Smrg
1896627f7eb2Smrg /* sizes(idx) = ... */
1897627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (sizes);
1898627f7eb2Smrg block->expr1->ref = gfc_get_ref ();
1899627f7eb2Smrg block->expr1->ref->type = REF_ARRAY;
1900627f7eb2Smrg block->expr1->ref->u.ar.type = AR_ELEMENT;
1901627f7eb2Smrg block->expr1->ref->u.ar.dimen = 1;
1902627f7eb2Smrg block->expr1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1903627f7eb2Smrg block->expr1->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx);
1904627f7eb2Smrg block->expr1->ref->u.ar.as = sizes->as;
1905627f7eb2Smrg
1906627f7eb2Smrg block->expr2 = gfc_get_expr ();
1907627f7eb2Smrg block->expr2->expr_type = EXPR_OP;
1908627f7eb2Smrg block->expr2->value.op.op = INTRINSIC_TIMES;
1909627f7eb2Smrg block->expr2->where = gfc_current_locus;
1910627f7eb2Smrg
1911627f7eb2Smrg /* sizes(idx-1). */
1912627f7eb2Smrg block->expr2->value.op.op1 = gfc_lval_expr_from_sym (sizes);
1913627f7eb2Smrg block->expr2->value.op.op1->ref = gfc_get_ref ();
1914627f7eb2Smrg block->expr2->value.op.op1->ref->type = REF_ARRAY;
1915627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.as = sizes->as;
1916627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.type = AR_ELEMENT;
1917627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.dimen = 1;
1918627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1919627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0] = gfc_get_expr ();
1920627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->expr_type = EXPR_OP;
1921627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->where = gfc_current_locus;
1922627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
1923627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op1
1924627f7eb2Smrg = gfc_lval_expr_from_sym (idx);
1925627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op2
1926627f7eb2Smrg = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1927627f7eb2Smrg block->expr2->value.op.op1->ref->u.ar.start[0]->ts
1928627f7eb2Smrg = block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op1->ts;
1929627f7eb2Smrg
1930627f7eb2Smrg /* size(array, dim=idx, kind=index_kind). */
1931627f7eb2Smrg block->expr2->value.op.op2
1932627f7eb2Smrg = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_SIZE, "size",
1933627f7eb2Smrg gfc_current_locus, 3,
1934627f7eb2Smrg gfc_lval_expr_from_sym (array),
1935627f7eb2Smrg gfc_lval_expr_from_sym (idx),
1936627f7eb2Smrg gfc_get_int_expr (gfc_index_integer_kind,
1937627f7eb2Smrg NULL,
1938627f7eb2Smrg gfc_index_integer_kind));
1939627f7eb2Smrg block->expr2->value.op.op2->ts.kind = gfc_index_integer_kind;
1940627f7eb2Smrg block->expr2->ts = idx->ts;
1941627f7eb2Smrg
1942627f7eb2Smrg /* if (strides (idx) /= sizes(idx-1)) is_contiguous = .false. */
1943627f7eb2Smrg block->next = gfc_get_code (EXEC_IF);
1944627f7eb2Smrg block = block->next;
1945627f7eb2Smrg
1946627f7eb2Smrg block->block = gfc_get_code (EXEC_IF);
1947627f7eb2Smrg block = block->block;
1948627f7eb2Smrg
1949627f7eb2Smrg /* if condition: strides(idx) /= sizes(idx-1). */
1950627f7eb2Smrg block->expr1 = gfc_get_expr ();
1951627f7eb2Smrg block->expr1->ts.type = BT_LOGICAL;
1952627f7eb2Smrg block->expr1->ts.kind = gfc_default_logical_kind;
1953627f7eb2Smrg block->expr1->expr_type = EXPR_OP;
1954627f7eb2Smrg block->expr1->where = gfc_current_locus;
1955627f7eb2Smrg block->expr1->value.op.op = INTRINSIC_NE;
1956627f7eb2Smrg
1957627f7eb2Smrg block->expr1->value.op.op1 = gfc_lval_expr_from_sym (strides);
1958627f7eb2Smrg block->expr1->value.op.op1->ref = gfc_get_ref ();
1959627f7eb2Smrg block->expr1->value.op.op1->ref->type = REF_ARRAY;
1960627f7eb2Smrg block->expr1->value.op.op1->ref->u.ar.type = AR_ELEMENT;
1961627f7eb2Smrg block->expr1->value.op.op1->ref->u.ar.dimen = 1;
1962627f7eb2Smrg block->expr1->value.op.op1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1963627f7eb2Smrg block->expr1->value.op.op1->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx);
1964627f7eb2Smrg block->expr1->value.op.op1->ref->u.ar.as = strides->as;
1965627f7eb2Smrg
1966627f7eb2Smrg block->expr1->value.op.op2 = gfc_lval_expr_from_sym (sizes);
1967627f7eb2Smrg block->expr1->value.op.op2->ref = gfc_get_ref ();
1968627f7eb2Smrg block->expr1->value.op.op2->ref->type = REF_ARRAY;
1969627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.as = sizes->as;
1970627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.type = AR_ELEMENT;
1971627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.dimen = 1;
1972627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
1973627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0] = gfc_get_expr ();
1974627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->expr_type = EXPR_OP;
1975627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->where = gfc_current_locus;
1976627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
1977627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op1
1978627f7eb2Smrg = gfc_lval_expr_from_sym (idx);
1979627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op2
1980627f7eb2Smrg = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
1981627f7eb2Smrg block->expr1->value.op.op2->ref->u.ar.start[0]->ts
1982627f7eb2Smrg = block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op1->ts;
1983627f7eb2Smrg
1984627f7eb2Smrg /* if body: is_contiguous = .false. */
1985627f7eb2Smrg block->next = gfc_get_code (EXEC_ASSIGN);
1986627f7eb2Smrg block = block->next;
1987627f7eb2Smrg block->expr1 = gfc_lval_expr_from_sym (is_contiguous);
1988627f7eb2Smrg block->expr2 = gfc_get_logical_expr (gfc_default_logical_kind,
1989627f7eb2Smrg &gfc_current_locus, false);
1990627f7eb2Smrg
1991627f7eb2Smrg /* Obtain the size (number of elements) of "array" MINUS ONE,
1992627f7eb2Smrg which is used in the scalarization. */
1993627f7eb2Smrg gfc_get_symbol ("nelem", sub_ns, &nelem);
1994627f7eb2Smrg nelem->ts.type = BT_INTEGER;
1995627f7eb2Smrg nelem->ts.kind = gfc_index_integer_kind;
1996627f7eb2Smrg nelem->attr.flavor = FL_VARIABLE;
1997627f7eb2Smrg nelem->attr.artificial = 1;
1998627f7eb2Smrg gfc_set_sym_referenced (nelem);
1999627f7eb2Smrg gfc_commit_symbol (nelem);
2000627f7eb2Smrg
2001627f7eb2Smrg /* nelem = sizes (rank) - 1. */
2002627f7eb2Smrg last_code->next = gfc_get_code (EXEC_ASSIGN);
2003627f7eb2Smrg last_code = last_code->next;
2004627f7eb2Smrg
2005627f7eb2Smrg last_code->expr1 = gfc_lval_expr_from_sym (nelem);
2006627f7eb2Smrg
2007627f7eb2Smrg last_code->expr2 = gfc_get_expr ();
2008627f7eb2Smrg last_code->expr2->expr_type = EXPR_OP;
2009627f7eb2Smrg last_code->expr2->value.op.op = INTRINSIC_MINUS;
2010627f7eb2Smrg last_code->expr2->value.op.op2
2011627f7eb2Smrg = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
2012627f7eb2Smrg last_code->expr2->ts = last_code->expr2->value.op.op2->ts;
2013627f7eb2Smrg last_code->expr2->where = gfc_current_locus;
2014627f7eb2Smrg
2015627f7eb2Smrg last_code->expr2->value.op.op1 = gfc_lval_expr_from_sym (sizes);
2016627f7eb2Smrg last_code->expr2->value.op.op1->ref = gfc_get_ref ();
2017627f7eb2Smrg last_code->expr2->value.op.op1->ref->type = REF_ARRAY;
2018627f7eb2Smrg last_code->expr2->value.op.op1->ref->u.ar.type = AR_ELEMENT;
2019627f7eb2Smrg last_code->expr2->value.op.op1->ref->u.ar.dimen = 1;
2020627f7eb2Smrg last_code->expr2->value.op.op1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
2021627f7eb2Smrg last_code->expr2->value.op.op1->ref->u.ar.start[0] = gfc_copy_expr (rank);
2022627f7eb2Smrg last_code->expr2->value.op.op1->ref->u.ar.as = sizes->as;
2023627f7eb2Smrg
2024627f7eb2Smrg /* Call final subroutines. We now generate code like:
2025627f7eb2Smrg use iso_c_binding
2026627f7eb2Smrg integer, pointer :: ptr
2027627f7eb2Smrg type(c_ptr) :: cptr
2028627f7eb2Smrg integer(c_intptr_t) :: i, addr
2029627f7eb2Smrg
2030627f7eb2Smrg select case (rank (array))
2031627f7eb2Smrg case (3)
2032627f7eb2Smrg ! If needed, the array is packed
2033627f7eb2Smrg call final_rank3 (array)
2034627f7eb2Smrg case default:
2035627f7eb2Smrg do i = 0, size (array)-1
2036627f7eb2Smrg addr = transfer (c_loc (array), addr) + i * stride
2037627f7eb2Smrg call c_f_pointer (transfer (addr, cptr), ptr)
2038627f7eb2Smrg call elemental_final (ptr)
2039627f7eb2Smrg end do
2040627f7eb2Smrg end select */
2041627f7eb2Smrg
2042627f7eb2Smrg if (derived->f2k_derived && derived->f2k_derived->finalizers)
2043627f7eb2Smrg {
2044627f7eb2Smrg gfc_finalizer *fini, *fini_elem = NULL;
2045627f7eb2Smrg
2046627f7eb2Smrg gfc_get_symbol ("ptr1", sub_ns, &ptr);
2047627f7eb2Smrg ptr->ts.type = BT_DERIVED;
2048627f7eb2Smrg ptr->ts.u.derived = derived;
2049627f7eb2Smrg ptr->attr.flavor = FL_VARIABLE;
2050627f7eb2Smrg ptr->attr.pointer = 1;
2051627f7eb2Smrg ptr->attr.artificial = 1;
2052627f7eb2Smrg gfc_set_sym_referenced (ptr);
2053627f7eb2Smrg gfc_commit_symbol (ptr);
2054627f7eb2Smrg
2055627f7eb2Smrg /* SELECT CASE (RANK (array)). */
2056627f7eb2Smrg last_code->next = gfc_get_code (EXEC_SELECT);
2057627f7eb2Smrg last_code = last_code->next;
2058627f7eb2Smrg last_code->expr1 = gfc_copy_expr (rank);
2059627f7eb2Smrg block = NULL;
2060627f7eb2Smrg
2061627f7eb2Smrg for (fini = derived->f2k_derived->finalizers; fini; fini = fini->next)
2062627f7eb2Smrg {
2063627f7eb2Smrg gcc_assert (fini->proc_tree); /* Should have been set in gfc_resolve_finalizers. */
2064627f7eb2Smrg if (fini->proc_tree->n.sym->attr.elemental)
2065627f7eb2Smrg {
2066627f7eb2Smrg fini_elem = fini;
2067627f7eb2Smrg continue;
2068627f7eb2Smrg }
2069627f7eb2Smrg
2070627f7eb2Smrg /* CASE (fini_rank). */
2071627f7eb2Smrg if (block)
2072627f7eb2Smrg {
2073627f7eb2Smrg block->block = gfc_get_code (EXEC_SELECT);
2074627f7eb2Smrg block = block->block;
2075627f7eb2Smrg }
2076627f7eb2Smrg else
2077627f7eb2Smrg {
2078627f7eb2Smrg block = gfc_get_code (EXEC_SELECT);
2079627f7eb2Smrg last_code->block = block;
2080627f7eb2Smrg }
2081627f7eb2Smrg block->ext.block.case_list = gfc_get_case ();
2082627f7eb2Smrg block->ext.block.case_list->where = gfc_current_locus;
2083627f7eb2Smrg if (fini->proc_tree->n.sym->formal->sym->attr.dimension)
2084627f7eb2Smrg block->ext.block.case_list->low
2085627f7eb2Smrg = gfc_get_int_expr (gfc_default_integer_kind, NULL,
2086627f7eb2Smrg fini->proc_tree->n.sym->formal->sym->as->rank);
2087627f7eb2Smrg else
2088627f7eb2Smrg block->ext.block.case_list->low
2089627f7eb2Smrg = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
2090627f7eb2Smrg block->ext.block.case_list->high
2091627f7eb2Smrg = gfc_copy_expr (block->ext.block.case_list->low);
2092627f7eb2Smrg
2093627f7eb2Smrg /* CALL fini_rank (array) - possibly with packing. */
2094627f7eb2Smrg if (fini->proc_tree->n.sym->formal->sym->attr.dimension)
2095627f7eb2Smrg finalizer_insert_packed_call (block, fini, array, byte_stride,
2096627f7eb2Smrg idx, ptr, nelem, strides,
2097627f7eb2Smrg sizes, idx2, offset, is_contiguous,
2098627f7eb2Smrg rank, sub_ns);
2099627f7eb2Smrg else
2100627f7eb2Smrg {
2101627f7eb2Smrg block->next = gfc_get_code (EXEC_CALL);
2102627f7eb2Smrg block->next->symtree = fini->proc_tree;
2103627f7eb2Smrg block->next->resolved_sym = fini->proc_tree->n.sym;
2104627f7eb2Smrg block->next->ext.actual = gfc_get_actual_arglist ();
2105627f7eb2Smrg block->next->ext.actual->expr = gfc_lval_expr_from_sym (array);
2106627f7eb2Smrg }
2107627f7eb2Smrg }
2108627f7eb2Smrg
2109627f7eb2Smrg /* Elemental call - scalarized. */
2110627f7eb2Smrg if (fini_elem)
2111627f7eb2Smrg {
2112627f7eb2Smrg /* CASE DEFAULT. */
2113627f7eb2Smrg if (block)
2114627f7eb2Smrg {
2115627f7eb2Smrg block->block = gfc_get_code (EXEC_SELECT);
2116627f7eb2Smrg block = block->block;
2117627f7eb2Smrg }
2118627f7eb2Smrg else
2119627f7eb2Smrg {
2120627f7eb2Smrg block = gfc_get_code (EXEC_SELECT);
2121627f7eb2Smrg last_code->block = block;
2122627f7eb2Smrg }
2123627f7eb2Smrg block->ext.block.case_list = gfc_get_case ();
2124627f7eb2Smrg
2125627f7eb2Smrg /* Create loop. */
2126627f7eb2Smrg iter = gfc_get_iterator ();
2127627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx);
2128627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
2129627f7eb2Smrg iter->end = gfc_lval_expr_from_sym (nelem);
2130627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
2131627f7eb2Smrg block->next = gfc_get_code (EXEC_DO);
2132627f7eb2Smrg block = block->next;
2133627f7eb2Smrg block->ext.iterator = iter;
2134627f7eb2Smrg block->block = gfc_get_code (EXEC_DO);
2135627f7eb2Smrg
2136627f7eb2Smrg /* Offset calculation. */
2137627f7eb2Smrg block = finalization_get_offset (idx, idx2, offset, strides, sizes,
2138627f7eb2Smrg byte_stride, rank, block->block,
2139627f7eb2Smrg sub_ns);
2140627f7eb2Smrg
2141627f7eb2Smrg /* Create code for
2142627f7eb2Smrg CALL C_F_POINTER (TRANSFER (TRANSFER (C_LOC (array, cptr), c_intptr)
2143627f7eb2Smrg + offset, c_ptr), ptr). */
2144627f7eb2Smrg block->next
2145627f7eb2Smrg = finalization_scalarizer (array, ptr,
2146627f7eb2Smrg gfc_lval_expr_from_sym (offset),
2147627f7eb2Smrg sub_ns);
2148627f7eb2Smrg block = block->next;
2149627f7eb2Smrg
2150627f7eb2Smrg /* CALL final_elemental (array). */
2151627f7eb2Smrg block->next = gfc_get_code (EXEC_CALL);
2152627f7eb2Smrg block = block->next;
2153627f7eb2Smrg block->symtree = fini_elem->proc_tree;
2154627f7eb2Smrg block->resolved_sym = fini_elem->proc_sym;
2155627f7eb2Smrg block->ext.actual = gfc_get_actual_arglist ();
2156627f7eb2Smrg block->ext.actual->expr = gfc_lval_expr_from_sym (ptr);
2157627f7eb2Smrg }
2158627f7eb2Smrg }
2159627f7eb2Smrg
2160627f7eb2Smrg /* Finalize and deallocate allocatable components. The same manual
2161627f7eb2Smrg scalarization is used as above. */
2162627f7eb2Smrg
2163627f7eb2Smrg if (finalizable_comp)
2164627f7eb2Smrg {
2165627f7eb2Smrg gfc_symbol *stat;
2166627f7eb2Smrg gfc_code *block = NULL;
2167627f7eb2Smrg
2168627f7eb2Smrg if (!ptr)
2169627f7eb2Smrg {
2170627f7eb2Smrg gfc_get_symbol ("ptr2", sub_ns, &ptr);
2171627f7eb2Smrg ptr->ts.type = BT_DERIVED;
2172627f7eb2Smrg ptr->ts.u.derived = derived;
2173627f7eb2Smrg ptr->attr.flavor = FL_VARIABLE;
2174627f7eb2Smrg ptr->attr.pointer = 1;
2175627f7eb2Smrg ptr->attr.artificial = 1;
2176627f7eb2Smrg gfc_set_sym_referenced (ptr);
2177627f7eb2Smrg gfc_commit_symbol (ptr);
2178627f7eb2Smrg }
2179627f7eb2Smrg
2180627f7eb2Smrg gfc_get_symbol ("ignore", sub_ns, &stat);
2181627f7eb2Smrg stat->attr.flavor = FL_VARIABLE;
2182627f7eb2Smrg stat->attr.artificial = 1;
2183627f7eb2Smrg stat->ts.type = BT_INTEGER;
2184627f7eb2Smrg stat->ts.kind = gfc_default_integer_kind;
2185627f7eb2Smrg gfc_set_sym_referenced (stat);
2186627f7eb2Smrg gfc_commit_symbol (stat);
2187627f7eb2Smrg
2188627f7eb2Smrg /* Create loop. */
2189627f7eb2Smrg iter = gfc_get_iterator ();
2190627f7eb2Smrg iter->var = gfc_lval_expr_from_sym (idx);
2191627f7eb2Smrg iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
2192627f7eb2Smrg iter->end = gfc_lval_expr_from_sym (nelem);
2193627f7eb2Smrg iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
2194627f7eb2Smrg last_code->next = gfc_get_code (EXEC_DO);
2195627f7eb2Smrg last_code = last_code->next;
2196627f7eb2Smrg last_code->ext.iterator = iter;
2197627f7eb2Smrg last_code->block = gfc_get_code (EXEC_DO);
2198627f7eb2Smrg
2199627f7eb2Smrg /* Offset calculation. */
2200627f7eb2Smrg block = finalization_get_offset (idx, idx2, offset, strides, sizes,
2201627f7eb2Smrg byte_stride, rank, last_code->block,
2202627f7eb2Smrg sub_ns);
2203627f7eb2Smrg
2204627f7eb2Smrg /* Create code for
2205627f7eb2Smrg CALL C_F_POINTER (TRANSFER (TRANSFER (C_LOC (array, cptr), c_intptr)
2206627f7eb2Smrg + idx * stride, c_ptr), ptr). */
2207627f7eb2Smrg block->next = finalization_scalarizer (array, ptr,
2208627f7eb2Smrg gfc_lval_expr_from_sym(offset),
2209627f7eb2Smrg sub_ns);
2210627f7eb2Smrg block = block->next;
2211627f7eb2Smrg
2212627f7eb2Smrg for (comp = derived->components; comp; comp = comp->next)
2213627f7eb2Smrg {
2214627f7eb2Smrg if (comp == derived->components && derived->attr.extension
2215627f7eb2Smrg && ancestor_wrapper && ancestor_wrapper->expr_type != EXPR_NULL)
2216627f7eb2Smrg continue;
2217627f7eb2Smrg
2218627f7eb2Smrg finalize_component (gfc_lval_expr_from_sym (ptr), derived, comp,
2219627f7eb2Smrg stat, fini_coarray, &block, sub_ns);
2220627f7eb2Smrg if (!last_code->block->next)
2221627f7eb2Smrg last_code->block->next = block;
2222627f7eb2Smrg }
2223627f7eb2Smrg
2224627f7eb2Smrg }
2225627f7eb2Smrg
2226627f7eb2Smrg /* Call the finalizer of the ancestor. */
2227627f7eb2Smrg if (ancestor_wrapper && ancestor_wrapper->expr_type != EXPR_NULL)
2228627f7eb2Smrg {
2229627f7eb2Smrg last_code->next = gfc_get_code (EXEC_CALL);
2230627f7eb2Smrg last_code = last_code->next;
2231627f7eb2Smrg last_code->symtree = ancestor_wrapper->symtree;
2232627f7eb2Smrg last_code->resolved_sym = ancestor_wrapper->symtree->n.sym;
2233627f7eb2Smrg
2234627f7eb2Smrg last_code->ext.actual = gfc_get_actual_arglist ();
2235627f7eb2Smrg last_code->ext.actual->expr = gfc_lval_expr_from_sym (array);
2236627f7eb2Smrg last_code->ext.actual->next = gfc_get_actual_arglist ();
2237627f7eb2Smrg last_code->ext.actual->next->expr = gfc_lval_expr_from_sym (byte_stride);
2238627f7eb2Smrg last_code->ext.actual->next->next = gfc_get_actual_arglist ();
2239627f7eb2Smrg last_code->ext.actual->next->next->expr
2240627f7eb2Smrg = gfc_lval_expr_from_sym (fini_coarray);
2241627f7eb2Smrg }
2242627f7eb2Smrg
2243627f7eb2Smrg gfc_free_expr (rank);
2244627f7eb2Smrg vtab_final->initializer = gfc_lval_expr_from_sym (final);
2245627f7eb2Smrg vtab_final->ts.interface = final;
2246627f7eb2Smrg free (name);
2247627f7eb2Smrg }
2248627f7eb2Smrg
2249627f7eb2Smrg
2250627f7eb2Smrg /* Add procedure pointers for all type-bound procedures to a vtab. */
2251627f7eb2Smrg
2252627f7eb2Smrg static void
add_procs_to_declared_vtab(gfc_symbol * derived,gfc_symbol * vtype)2253627f7eb2Smrg add_procs_to_declared_vtab (gfc_symbol *derived, gfc_symbol *vtype)
2254627f7eb2Smrg {
2255627f7eb2Smrg gfc_symbol* super_type;
2256627f7eb2Smrg
2257627f7eb2Smrg super_type = gfc_get_derived_super_type (derived);
2258627f7eb2Smrg
2259627f7eb2Smrg if (super_type && (super_type != derived))
2260627f7eb2Smrg {
2261627f7eb2Smrg /* Make sure that the PPCs appear in the same order as in the parent. */
2262627f7eb2Smrg copy_vtab_proc_comps (super_type, vtype);
2263627f7eb2Smrg /* Only needed to get the PPC initializers right. */
2264627f7eb2Smrg add_procs_to_declared_vtab (super_type, vtype);
2265627f7eb2Smrg }
2266627f7eb2Smrg
2267627f7eb2Smrg if (derived->f2k_derived && derived->f2k_derived->tb_sym_root)
2268627f7eb2Smrg add_procs_to_declared_vtab1 (derived->f2k_derived->tb_sym_root, vtype);
2269627f7eb2Smrg
2270627f7eb2Smrg if (derived->f2k_derived && derived->f2k_derived->tb_uop_root)
2271627f7eb2Smrg add_procs_to_declared_vtab1 (derived->f2k_derived->tb_uop_root, vtype);
2272627f7eb2Smrg }
2273627f7eb2Smrg
2274627f7eb2Smrg
2275627f7eb2Smrg /* Find or generate the symbol for a derived type's vtab. */
2276627f7eb2Smrg
2277627f7eb2Smrg gfc_symbol *
gfc_find_derived_vtab(gfc_symbol * derived)2278627f7eb2Smrg gfc_find_derived_vtab (gfc_symbol *derived)
2279627f7eb2Smrg {
2280627f7eb2Smrg gfc_namespace *ns;
2281627f7eb2Smrg gfc_symbol *vtab = NULL, *vtype = NULL, *found_sym = NULL, *def_init = NULL;
2282627f7eb2Smrg gfc_symbol *copy = NULL, *src = NULL, *dst = NULL;
2283627f7eb2Smrg gfc_gsymbol *gsym = NULL;
2284627f7eb2Smrg gfc_symbol *dealloc = NULL, *arg = NULL;
2285627f7eb2Smrg
2286627f7eb2Smrg if (derived->attr.pdt_template)
2287627f7eb2Smrg return NULL;
2288627f7eb2Smrg
2289627f7eb2Smrg /* Find the top-level namespace. */
2290627f7eb2Smrg for (ns = gfc_current_ns; ns; ns = ns->parent)
2291627f7eb2Smrg if (!ns->parent)
2292627f7eb2Smrg break;
2293627f7eb2Smrg
2294627f7eb2Smrg /* If the type is a class container, use the underlying derived type. */
2295627f7eb2Smrg if (!derived->attr.unlimited_polymorphic && derived->attr.is_class)
2296627f7eb2Smrg derived = gfc_get_derived_super_type (derived);
2297627f7eb2Smrg
2298627f7eb2Smrg if (!derived)
2299627f7eb2Smrg return NULL;
2300627f7eb2Smrg
2301*4c3eb207Smrg if (!derived->name)
2302*4c3eb207Smrg return NULL;
2303*4c3eb207Smrg
2304627f7eb2Smrg /* Find the gsymbol for the module of use associated derived types. */
2305627f7eb2Smrg if ((derived->attr.use_assoc || derived->attr.used_in_submodule)
2306627f7eb2Smrg && !derived->attr.vtype && !derived->attr.is_class)
2307627f7eb2Smrg gsym = gfc_find_gsymbol (gfc_gsym_root, derived->module);
2308627f7eb2Smrg else
2309627f7eb2Smrg gsym = NULL;
2310627f7eb2Smrg
2311627f7eb2Smrg /* Work in the gsymbol namespace if the top-level namespace is a module.
2312627f7eb2Smrg This ensures that the vtable is unique, which is required since we use
2313627f7eb2Smrg its address in SELECT TYPE. */
2314627f7eb2Smrg if (gsym && gsym->ns && ns && ns->proc_name
2315627f7eb2Smrg && ns->proc_name->attr.flavor == FL_MODULE)
2316627f7eb2Smrg ns = gsym->ns;
2317627f7eb2Smrg
2318627f7eb2Smrg if (ns)
2319627f7eb2Smrg {
2320627f7eb2Smrg char tname[GFC_MAX_SYMBOL_LEN+1];
2321627f7eb2Smrg char *name;
2322627f7eb2Smrg
2323627f7eb2Smrg get_unique_hashed_string (tname, derived);
2324627f7eb2Smrg name = xasprintf ("__vtab_%s", tname);
2325627f7eb2Smrg
2326627f7eb2Smrg /* Look for the vtab symbol in various namespaces. */
2327627f7eb2Smrg if (gsym && gsym->ns)
2328627f7eb2Smrg {
2329627f7eb2Smrg gfc_find_symbol (name, gsym->ns, 0, &vtab);
2330627f7eb2Smrg if (vtab)
2331627f7eb2Smrg ns = gsym->ns;
2332627f7eb2Smrg }
2333627f7eb2Smrg if (vtab == NULL)
2334627f7eb2Smrg gfc_find_symbol (name, gfc_current_ns, 0, &vtab);
2335627f7eb2Smrg if (vtab == NULL)
2336627f7eb2Smrg gfc_find_symbol (name, ns, 0, &vtab);
2337627f7eb2Smrg if (vtab == NULL)
2338627f7eb2Smrg gfc_find_symbol (name, derived->ns, 0, &vtab);
2339627f7eb2Smrg
2340627f7eb2Smrg if (vtab == NULL)
2341627f7eb2Smrg {
2342627f7eb2Smrg gfc_get_symbol (name, ns, &vtab);
2343627f7eb2Smrg vtab->ts.type = BT_DERIVED;
2344627f7eb2Smrg if (!gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
2345627f7eb2Smrg &gfc_current_locus))
2346627f7eb2Smrg goto cleanup;
2347627f7eb2Smrg vtab->attr.target = 1;
2348627f7eb2Smrg vtab->attr.save = SAVE_IMPLICIT;
2349627f7eb2Smrg vtab->attr.vtab = 1;
2350627f7eb2Smrg vtab->attr.access = ACCESS_PUBLIC;
2351627f7eb2Smrg gfc_set_sym_referenced (vtab);
2352627f7eb2Smrg name = xasprintf ("__vtype_%s", tname);
2353627f7eb2Smrg
2354627f7eb2Smrg gfc_find_symbol (name, ns, 0, &vtype);
2355627f7eb2Smrg if (vtype == NULL)
2356627f7eb2Smrg {
2357627f7eb2Smrg gfc_component *c;
2358627f7eb2Smrg gfc_symbol *parent = NULL, *parent_vtab = NULL;
2359627f7eb2Smrg bool rdt = false;
2360627f7eb2Smrg
2361627f7eb2Smrg /* Is this a derived type with recursive allocatable
2362627f7eb2Smrg components? */
2363627f7eb2Smrg c = (derived->attr.unlimited_polymorphic
2364627f7eb2Smrg || derived->attr.abstract) ?
2365627f7eb2Smrg NULL : derived->components;
2366627f7eb2Smrg for (; c; c= c->next)
2367627f7eb2Smrg if (c->ts.type == BT_DERIVED
2368627f7eb2Smrg && c->ts.u.derived == derived)
2369627f7eb2Smrg {
2370627f7eb2Smrg rdt = true;
2371627f7eb2Smrg break;
2372627f7eb2Smrg }
2373627f7eb2Smrg
2374627f7eb2Smrg gfc_get_symbol (name, ns, &vtype);
2375627f7eb2Smrg if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
2376627f7eb2Smrg &gfc_current_locus))
2377627f7eb2Smrg goto cleanup;
2378627f7eb2Smrg vtype->attr.access = ACCESS_PUBLIC;
2379627f7eb2Smrg vtype->attr.vtype = 1;
2380627f7eb2Smrg gfc_set_sym_referenced (vtype);
2381627f7eb2Smrg
2382627f7eb2Smrg /* Add component '_hash'. */
2383627f7eb2Smrg if (!gfc_add_component (vtype, "_hash", &c))
2384627f7eb2Smrg goto cleanup;
2385627f7eb2Smrg c->ts.type = BT_INTEGER;
2386627f7eb2Smrg c->ts.kind = 4;
2387627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2388627f7eb2Smrg c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
2389627f7eb2Smrg NULL, derived->hash_value);
2390627f7eb2Smrg
2391627f7eb2Smrg /* Add component '_size'. */
2392627f7eb2Smrg if (!gfc_add_component (vtype, "_size", &c))
2393627f7eb2Smrg goto cleanup;
2394627f7eb2Smrg c->ts.type = BT_INTEGER;
2395627f7eb2Smrg c->ts.kind = gfc_size_kind;
2396627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2397627f7eb2Smrg /* Remember the derived type in ts.u.derived,
2398627f7eb2Smrg so that the correct initializer can be set later on
2399627f7eb2Smrg (in gfc_conv_structure). */
2400627f7eb2Smrg c->ts.u.derived = derived;
2401627f7eb2Smrg c->initializer = gfc_get_int_expr (gfc_size_kind,
2402627f7eb2Smrg NULL, 0);
2403627f7eb2Smrg
2404627f7eb2Smrg /* Add component _extends. */
2405627f7eb2Smrg if (!gfc_add_component (vtype, "_extends", &c))
2406627f7eb2Smrg goto cleanup;
2407627f7eb2Smrg c->attr.pointer = 1;
2408627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2409627f7eb2Smrg if (!derived->attr.unlimited_polymorphic)
2410627f7eb2Smrg parent = gfc_get_derived_super_type (derived);
2411627f7eb2Smrg else
2412627f7eb2Smrg parent = NULL;
2413627f7eb2Smrg
2414627f7eb2Smrg if (parent)
2415627f7eb2Smrg {
2416627f7eb2Smrg parent_vtab = gfc_find_derived_vtab (parent);
2417627f7eb2Smrg c->ts.type = BT_DERIVED;
2418627f7eb2Smrg c->ts.u.derived = parent_vtab->ts.u.derived;
2419627f7eb2Smrg c->initializer = gfc_get_expr ();
2420627f7eb2Smrg c->initializer->expr_type = EXPR_VARIABLE;
2421627f7eb2Smrg gfc_find_sym_tree (parent_vtab->name, parent_vtab->ns,
2422627f7eb2Smrg 0, &c->initializer->symtree);
2423627f7eb2Smrg }
2424627f7eb2Smrg else
2425627f7eb2Smrg {
2426627f7eb2Smrg c->ts.type = BT_DERIVED;
2427627f7eb2Smrg c->ts.u.derived = vtype;
2428627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2429627f7eb2Smrg }
2430627f7eb2Smrg
2431627f7eb2Smrg if (!derived->attr.unlimited_polymorphic
2432627f7eb2Smrg && derived->components == NULL
2433627f7eb2Smrg && !derived->attr.zero_comp)
2434627f7eb2Smrg {
2435627f7eb2Smrg /* At this point an error must have occurred.
2436627f7eb2Smrg Prevent further errors on the vtype components. */
2437627f7eb2Smrg found_sym = vtab;
2438627f7eb2Smrg goto have_vtype;
2439627f7eb2Smrg }
2440627f7eb2Smrg
2441627f7eb2Smrg /* Add component _def_init. */
2442627f7eb2Smrg if (!gfc_add_component (vtype, "_def_init", &c))
2443627f7eb2Smrg goto cleanup;
2444627f7eb2Smrg c->attr.pointer = 1;
2445627f7eb2Smrg c->attr.artificial = 1;
2446627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2447627f7eb2Smrg c->ts.type = BT_DERIVED;
2448627f7eb2Smrg c->ts.u.derived = derived;
2449627f7eb2Smrg if (derived->attr.unlimited_polymorphic
2450627f7eb2Smrg || derived->attr.abstract)
2451627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2452627f7eb2Smrg else
2453627f7eb2Smrg {
2454627f7eb2Smrg /* Construct default initialization variable. */
2455627f7eb2Smrg name = xasprintf ("__def_init_%s", tname);
2456627f7eb2Smrg gfc_get_symbol (name, ns, &def_init);
2457627f7eb2Smrg def_init->attr.target = 1;
2458627f7eb2Smrg def_init->attr.artificial = 1;
2459627f7eb2Smrg def_init->attr.save = SAVE_IMPLICIT;
2460627f7eb2Smrg def_init->attr.access = ACCESS_PUBLIC;
2461627f7eb2Smrg def_init->attr.flavor = FL_VARIABLE;
2462627f7eb2Smrg gfc_set_sym_referenced (def_init);
2463627f7eb2Smrg def_init->ts.type = BT_DERIVED;
2464627f7eb2Smrg def_init->ts.u.derived = derived;
2465627f7eb2Smrg def_init->value = gfc_default_initializer (&def_init->ts);
2466627f7eb2Smrg
2467627f7eb2Smrg c->initializer = gfc_lval_expr_from_sym (def_init);
2468627f7eb2Smrg }
2469627f7eb2Smrg
2470627f7eb2Smrg /* Add component _copy. */
2471627f7eb2Smrg if (!gfc_add_component (vtype, "_copy", &c))
2472627f7eb2Smrg goto cleanup;
2473627f7eb2Smrg c->attr.proc_pointer = 1;
2474627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2475627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
2476627f7eb2Smrg c->tb->ppc = 1;
2477627f7eb2Smrg if (derived->attr.unlimited_polymorphic
2478627f7eb2Smrg || derived->attr.abstract)
2479627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2480627f7eb2Smrg else
2481627f7eb2Smrg {
2482627f7eb2Smrg /* Set up namespace. */
2483627f7eb2Smrg gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
2484627f7eb2Smrg sub_ns->sibling = ns->contained;
2485627f7eb2Smrg ns->contained = sub_ns;
2486627f7eb2Smrg sub_ns->resolved = 1;
2487627f7eb2Smrg /* Set up procedure symbol. */
2488627f7eb2Smrg name = xasprintf ("__copy_%s", tname);
2489627f7eb2Smrg gfc_get_symbol (name, sub_ns, ©);
2490627f7eb2Smrg sub_ns->proc_name = copy;
2491627f7eb2Smrg copy->attr.flavor = FL_PROCEDURE;
2492627f7eb2Smrg copy->attr.subroutine = 1;
2493627f7eb2Smrg copy->attr.pure = 1;
2494627f7eb2Smrg copy->attr.artificial = 1;
2495627f7eb2Smrg copy->attr.if_source = IFSRC_DECL;
2496627f7eb2Smrg /* This is elemental so that arrays are automatically
2497627f7eb2Smrg treated correctly by the scalarizer. */
2498627f7eb2Smrg copy->attr.elemental = 1;
2499627f7eb2Smrg if (ns->proc_name->attr.flavor == FL_MODULE)
2500627f7eb2Smrg copy->module = ns->proc_name->name;
2501627f7eb2Smrg gfc_set_sym_referenced (copy);
2502627f7eb2Smrg /* Set up formal arguments. */
2503627f7eb2Smrg gfc_get_symbol ("src", sub_ns, &src);
2504627f7eb2Smrg src->ts.type = BT_DERIVED;
2505627f7eb2Smrg src->ts.u.derived = derived;
2506627f7eb2Smrg src->attr.flavor = FL_VARIABLE;
2507627f7eb2Smrg src->attr.dummy = 1;
2508627f7eb2Smrg src->attr.artificial = 1;
2509627f7eb2Smrg src->attr.intent = INTENT_IN;
2510627f7eb2Smrg gfc_set_sym_referenced (src);
2511627f7eb2Smrg copy->formal = gfc_get_formal_arglist ();
2512627f7eb2Smrg copy->formal->sym = src;
2513627f7eb2Smrg gfc_get_symbol ("dst", sub_ns, &dst);
2514627f7eb2Smrg dst->ts.type = BT_DERIVED;
2515627f7eb2Smrg dst->ts.u.derived = derived;
2516627f7eb2Smrg dst->attr.flavor = FL_VARIABLE;
2517627f7eb2Smrg dst->attr.dummy = 1;
2518627f7eb2Smrg dst->attr.artificial = 1;
2519627f7eb2Smrg dst->attr.intent = INTENT_INOUT;
2520627f7eb2Smrg gfc_set_sym_referenced (dst);
2521627f7eb2Smrg copy->formal->next = gfc_get_formal_arglist ();
2522627f7eb2Smrg copy->formal->next->sym = dst;
2523627f7eb2Smrg /* Set up code. */
2524627f7eb2Smrg sub_ns->code = gfc_get_code (EXEC_INIT_ASSIGN);
2525627f7eb2Smrg sub_ns->code->expr1 = gfc_lval_expr_from_sym (dst);
2526627f7eb2Smrg sub_ns->code->expr2 = gfc_lval_expr_from_sym (src);
2527627f7eb2Smrg /* Set initializer. */
2528627f7eb2Smrg c->initializer = gfc_lval_expr_from_sym (copy);
2529627f7eb2Smrg c->ts.interface = copy;
2530627f7eb2Smrg }
2531627f7eb2Smrg
2532627f7eb2Smrg /* Add component _final, which contains a procedure pointer to
2533627f7eb2Smrg a wrapper which handles both the freeing of allocatable
2534627f7eb2Smrg components and the calls to finalization subroutines.
2535627f7eb2Smrg Note: The actual wrapper function can only be generated
2536627f7eb2Smrg at resolution time. */
2537627f7eb2Smrg if (!gfc_add_component (vtype, "_final", &c))
2538627f7eb2Smrg goto cleanup;
2539627f7eb2Smrg c->attr.proc_pointer = 1;
2540627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2541627f7eb2Smrg c->attr.artificial = 1;
2542627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
2543627f7eb2Smrg c->tb->ppc = 1;
2544627f7eb2Smrg generate_finalization_wrapper (derived, ns, tname, c);
2545627f7eb2Smrg
2546627f7eb2Smrg /* Add component _deallocate. */
2547627f7eb2Smrg if (!gfc_add_component (vtype, "_deallocate", &c))
2548627f7eb2Smrg goto cleanup;
2549627f7eb2Smrg c->attr.proc_pointer = 1;
2550627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2551627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
2552627f7eb2Smrg c->tb->ppc = 1;
2553627f7eb2Smrg if (derived->attr.unlimited_polymorphic
2554627f7eb2Smrg || derived->attr.abstract
2555627f7eb2Smrg || !rdt)
2556627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2557627f7eb2Smrg else
2558627f7eb2Smrg {
2559627f7eb2Smrg /* Set up namespace. */
2560627f7eb2Smrg gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
2561627f7eb2Smrg
2562627f7eb2Smrg sub_ns->sibling = ns->contained;
2563627f7eb2Smrg ns->contained = sub_ns;
2564627f7eb2Smrg sub_ns->resolved = 1;
2565627f7eb2Smrg /* Set up procedure symbol. */
2566627f7eb2Smrg name = xasprintf ("__deallocate_%s", tname);
2567627f7eb2Smrg gfc_get_symbol (name, sub_ns, &dealloc);
2568627f7eb2Smrg sub_ns->proc_name = dealloc;
2569627f7eb2Smrg dealloc->attr.flavor = FL_PROCEDURE;
2570627f7eb2Smrg dealloc->attr.subroutine = 1;
2571627f7eb2Smrg dealloc->attr.pure = 1;
2572627f7eb2Smrg dealloc->attr.artificial = 1;
2573627f7eb2Smrg dealloc->attr.if_source = IFSRC_DECL;
2574627f7eb2Smrg
2575627f7eb2Smrg if (ns->proc_name->attr.flavor == FL_MODULE)
2576627f7eb2Smrg dealloc->module = ns->proc_name->name;
2577627f7eb2Smrg gfc_set_sym_referenced (dealloc);
2578627f7eb2Smrg /* Set up formal argument. */
2579627f7eb2Smrg gfc_get_symbol ("arg", sub_ns, &arg);
2580627f7eb2Smrg arg->ts.type = BT_DERIVED;
2581627f7eb2Smrg arg->ts.u.derived = derived;
2582627f7eb2Smrg arg->attr.flavor = FL_VARIABLE;
2583627f7eb2Smrg arg->attr.dummy = 1;
2584627f7eb2Smrg arg->attr.artificial = 1;
2585627f7eb2Smrg arg->attr.intent = INTENT_INOUT;
2586627f7eb2Smrg arg->attr.dimension = 1;
2587627f7eb2Smrg arg->attr.allocatable = 1;
2588627f7eb2Smrg arg->as = gfc_get_array_spec();
2589627f7eb2Smrg arg->as->type = AS_ASSUMED_SHAPE;
2590627f7eb2Smrg arg->as->rank = 1;
2591627f7eb2Smrg arg->as->lower[0] = gfc_get_int_expr (gfc_default_integer_kind,
2592627f7eb2Smrg NULL, 1);
2593627f7eb2Smrg gfc_set_sym_referenced (arg);
2594627f7eb2Smrg dealloc->formal = gfc_get_formal_arglist ();
2595627f7eb2Smrg dealloc->formal->sym = arg;
2596627f7eb2Smrg /* Set up code. */
2597627f7eb2Smrg sub_ns->code = gfc_get_code (EXEC_DEALLOCATE);
2598627f7eb2Smrg sub_ns->code->ext.alloc.list = gfc_get_alloc ();
2599627f7eb2Smrg sub_ns->code->ext.alloc.list->expr
2600627f7eb2Smrg = gfc_lval_expr_from_sym (arg);
2601627f7eb2Smrg /* Set initializer. */
2602627f7eb2Smrg c->initializer = gfc_lval_expr_from_sym (dealloc);
2603627f7eb2Smrg c->ts.interface = dealloc;
2604627f7eb2Smrg }
2605627f7eb2Smrg
2606627f7eb2Smrg /* Add procedure pointers for type-bound procedures. */
2607627f7eb2Smrg if (!derived->attr.unlimited_polymorphic)
2608627f7eb2Smrg add_procs_to_declared_vtab (derived, vtype);
2609627f7eb2Smrg }
2610627f7eb2Smrg
2611627f7eb2Smrg have_vtype:
2612627f7eb2Smrg vtab->ts.u.derived = vtype;
2613627f7eb2Smrg vtab->value = gfc_default_initializer (&vtab->ts);
2614627f7eb2Smrg }
2615627f7eb2Smrg free (name);
2616627f7eb2Smrg }
2617627f7eb2Smrg
2618627f7eb2Smrg found_sym = vtab;
2619627f7eb2Smrg
2620627f7eb2Smrg cleanup:
2621627f7eb2Smrg /* It is unexpected to have some symbols added at resolution or code
2622627f7eb2Smrg generation time. We commit the changes in order to keep a clean state. */
2623627f7eb2Smrg if (found_sym)
2624627f7eb2Smrg {
2625627f7eb2Smrg gfc_commit_symbol (vtab);
2626627f7eb2Smrg if (vtype)
2627627f7eb2Smrg gfc_commit_symbol (vtype);
2628627f7eb2Smrg if (def_init)
2629627f7eb2Smrg gfc_commit_symbol (def_init);
2630627f7eb2Smrg if (copy)
2631627f7eb2Smrg gfc_commit_symbol (copy);
2632627f7eb2Smrg if (src)
2633627f7eb2Smrg gfc_commit_symbol (src);
2634627f7eb2Smrg if (dst)
2635627f7eb2Smrg gfc_commit_symbol (dst);
2636627f7eb2Smrg if (dealloc)
2637627f7eb2Smrg gfc_commit_symbol (dealloc);
2638627f7eb2Smrg if (arg)
2639627f7eb2Smrg gfc_commit_symbol (arg);
2640627f7eb2Smrg }
2641627f7eb2Smrg else
2642627f7eb2Smrg gfc_undo_symbols ();
2643627f7eb2Smrg
2644627f7eb2Smrg return found_sym;
2645627f7eb2Smrg }
2646627f7eb2Smrg
2647627f7eb2Smrg
2648627f7eb2Smrg /* Check if a derived type is finalizable. That is the case if it
2649627f7eb2Smrg (1) has a FINAL subroutine or
2650627f7eb2Smrg (2) has a nonpointer nonallocatable component of finalizable type.
2651627f7eb2Smrg If it is finalizable, return an expression containing the
2652627f7eb2Smrg finalization wrapper. */
2653627f7eb2Smrg
2654627f7eb2Smrg bool
gfc_is_finalizable(gfc_symbol * derived,gfc_expr ** final_expr)2655627f7eb2Smrg gfc_is_finalizable (gfc_symbol *derived, gfc_expr **final_expr)
2656627f7eb2Smrg {
2657627f7eb2Smrg gfc_symbol *vtab;
2658627f7eb2Smrg gfc_component *c;
2659627f7eb2Smrg
2660627f7eb2Smrg /* (1) Check for FINAL subroutines. */
2661627f7eb2Smrg if (derived->f2k_derived && derived->f2k_derived->finalizers)
2662627f7eb2Smrg goto yes;
2663627f7eb2Smrg
2664627f7eb2Smrg /* (2) Check for components of finalizable type. */
2665627f7eb2Smrg for (c = derived->components; c; c = c->next)
2666627f7eb2Smrg if (c->ts.type == BT_DERIVED
2667627f7eb2Smrg && !c->attr.pointer && !c->attr.proc_pointer && !c->attr.allocatable
2668627f7eb2Smrg && gfc_is_finalizable (c->ts.u.derived, NULL))
2669627f7eb2Smrg goto yes;
2670627f7eb2Smrg
2671627f7eb2Smrg return false;
2672627f7eb2Smrg
2673627f7eb2Smrg yes:
2674627f7eb2Smrg /* Make sure vtab is generated. */
2675627f7eb2Smrg vtab = gfc_find_derived_vtab (derived);
2676627f7eb2Smrg if (final_expr)
2677627f7eb2Smrg {
2678627f7eb2Smrg /* Return finalizer expression. */
2679627f7eb2Smrg gfc_component *final;
2680627f7eb2Smrg final = vtab->ts.u.derived->components->next->next->next->next->next;
2681627f7eb2Smrg gcc_assert (strcmp (final->name, "_final") == 0);
2682627f7eb2Smrg gcc_assert (final->initializer
2683627f7eb2Smrg && final->initializer->expr_type != EXPR_NULL);
2684627f7eb2Smrg *final_expr = final->initializer;
2685627f7eb2Smrg }
2686627f7eb2Smrg return true;
2687627f7eb2Smrg }
2688627f7eb2Smrg
2689627f7eb2Smrg
2690627f7eb2Smrg /* Find (or generate) the symbol for an intrinsic type's vtab. This is
2691627f7eb2Smrg needed to support unlimited polymorphism. */
2692627f7eb2Smrg
2693627f7eb2Smrg static gfc_symbol *
find_intrinsic_vtab(gfc_typespec * ts)2694627f7eb2Smrg find_intrinsic_vtab (gfc_typespec *ts)
2695627f7eb2Smrg {
2696627f7eb2Smrg gfc_namespace *ns;
2697627f7eb2Smrg gfc_symbol *vtab = NULL, *vtype = NULL, *found_sym = NULL;
2698627f7eb2Smrg gfc_symbol *copy = NULL, *src = NULL, *dst = NULL;
2699627f7eb2Smrg
2700627f7eb2Smrg /* Find the top-level namespace. */
2701627f7eb2Smrg for (ns = gfc_current_ns; ns; ns = ns->parent)
2702627f7eb2Smrg if (!ns->parent)
2703627f7eb2Smrg break;
2704627f7eb2Smrg
2705627f7eb2Smrg if (ns)
2706627f7eb2Smrg {
2707627f7eb2Smrg char tname[GFC_MAX_SYMBOL_LEN+1];
2708627f7eb2Smrg char *name;
2709627f7eb2Smrg
2710627f7eb2Smrg /* Encode all types as TYPENAME_KIND_ including especially character
2711627f7eb2Smrg arrays, whose length is now consistently stored in the _len component
2712627f7eb2Smrg of the class-variable. */
2713627f7eb2Smrg sprintf (tname, "%s_%d_", gfc_basic_typename (ts->type), ts->kind);
2714627f7eb2Smrg name = xasprintf ("__vtab_%s", tname);
2715627f7eb2Smrg
2716627f7eb2Smrg /* Look for the vtab symbol in the top-level namespace only. */
2717627f7eb2Smrg gfc_find_symbol (name, ns, 0, &vtab);
2718627f7eb2Smrg
2719627f7eb2Smrg if (vtab == NULL)
2720627f7eb2Smrg {
2721627f7eb2Smrg gfc_get_symbol (name, ns, &vtab);
2722627f7eb2Smrg vtab->ts.type = BT_DERIVED;
2723627f7eb2Smrg if (!gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
2724627f7eb2Smrg &gfc_current_locus))
2725627f7eb2Smrg goto cleanup;
2726627f7eb2Smrg vtab->attr.target = 1;
2727627f7eb2Smrg vtab->attr.save = SAVE_IMPLICIT;
2728627f7eb2Smrg vtab->attr.vtab = 1;
2729627f7eb2Smrg vtab->attr.access = ACCESS_PUBLIC;
2730627f7eb2Smrg gfc_set_sym_referenced (vtab);
2731627f7eb2Smrg name = xasprintf ("__vtype_%s", tname);
2732627f7eb2Smrg
2733627f7eb2Smrg gfc_find_symbol (name, ns, 0, &vtype);
2734627f7eb2Smrg if (vtype == NULL)
2735627f7eb2Smrg {
2736627f7eb2Smrg gfc_component *c;
2737627f7eb2Smrg int hash;
2738627f7eb2Smrg gfc_namespace *sub_ns;
2739627f7eb2Smrg gfc_namespace *contained;
2740627f7eb2Smrg gfc_expr *e;
2741627f7eb2Smrg size_t e_size;
2742627f7eb2Smrg
2743627f7eb2Smrg gfc_get_symbol (name, ns, &vtype);
2744627f7eb2Smrg if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
2745627f7eb2Smrg &gfc_current_locus))
2746627f7eb2Smrg goto cleanup;
2747627f7eb2Smrg vtype->attr.access = ACCESS_PUBLIC;
2748627f7eb2Smrg vtype->attr.vtype = 1;
2749627f7eb2Smrg gfc_set_sym_referenced (vtype);
2750627f7eb2Smrg
2751627f7eb2Smrg /* Add component '_hash'. */
2752627f7eb2Smrg if (!gfc_add_component (vtype, "_hash", &c))
2753627f7eb2Smrg goto cleanup;
2754627f7eb2Smrg c->ts.type = BT_INTEGER;
2755627f7eb2Smrg c->ts.kind = 4;
2756627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2757627f7eb2Smrg hash = gfc_intrinsic_hash_value (ts);
2758627f7eb2Smrg c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
2759627f7eb2Smrg NULL, hash);
2760627f7eb2Smrg
2761627f7eb2Smrg /* Add component '_size'. */
2762627f7eb2Smrg if (!gfc_add_component (vtype, "_size", &c))
2763627f7eb2Smrg goto cleanup;
2764627f7eb2Smrg c->ts.type = BT_INTEGER;
2765627f7eb2Smrg c->ts.kind = gfc_size_kind;
2766627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2767627f7eb2Smrg
2768627f7eb2Smrg /* Build a minimal expression to make use of
2769627f7eb2Smrg target-memory.c/gfc_element_size for 'size'. Special handling
2770627f7eb2Smrg for character arrays, that are not constant sized: to support
2771627f7eb2Smrg len (str) * kind, only the kind information is stored in the
2772627f7eb2Smrg vtab. */
2773627f7eb2Smrg e = gfc_get_expr ();
2774627f7eb2Smrg e->ts = *ts;
2775627f7eb2Smrg e->expr_type = EXPR_VARIABLE;
2776627f7eb2Smrg if (ts->type == BT_CHARACTER)
2777627f7eb2Smrg e_size = ts->kind;
2778627f7eb2Smrg else
2779627f7eb2Smrg gfc_element_size (e, &e_size);
2780627f7eb2Smrg c->initializer = gfc_get_int_expr (gfc_size_kind,
2781627f7eb2Smrg NULL,
2782627f7eb2Smrg e_size);
2783627f7eb2Smrg gfc_free_expr (e);
2784627f7eb2Smrg
2785627f7eb2Smrg /* Add component _extends. */
2786627f7eb2Smrg if (!gfc_add_component (vtype, "_extends", &c))
2787627f7eb2Smrg goto cleanup;
2788627f7eb2Smrg c->attr.pointer = 1;
2789627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2790627f7eb2Smrg c->ts.type = BT_VOID;
2791627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2792627f7eb2Smrg
2793627f7eb2Smrg /* Add component _def_init. */
2794627f7eb2Smrg if (!gfc_add_component (vtype, "_def_init", &c))
2795627f7eb2Smrg goto cleanup;
2796627f7eb2Smrg c->attr.pointer = 1;
2797627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2798627f7eb2Smrg c->ts.type = BT_VOID;
2799627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2800627f7eb2Smrg
2801627f7eb2Smrg /* Add component _copy. */
2802627f7eb2Smrg if (!gfc_add_component (vtype, "_copy", &c))
2803627f7eb2Smrg goto cleanup;
2804627f7eb2Smrg c->attr.proc_pointer = 1;
2805627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2806627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
2807627f7eb2Smrg c->tb->ppc = 1;
2808627f7eb2Smrg
2809627f7eb2Smrg if (ts->type != BT_CHARACTER)
2810627f7eb2Smrg name = xasprintf ("__copy_%s", tname);
2811627f7eb2Smrg else
2812627f7eb2Smrg {
2813627f7eb2Smrg /* __copy is always the same for characters.
2814627f7eb2Smrg Check to see if copy function already exists. */
2815627f7eb2Smrg name = xasprintf ("__copy_character_%d", ts->kind);
2816627f7eb2Smrg contained = ns->contained;
2817627f7eb2Smrg for (; contained; contained = contained->sibling)
2818627f7eb2Smrg if (contained->proc_name
2819627f7eb2Smrg && strcmp (name, contained->proc_name->name) == 0)
2820627f7eb2Smrg {
2821627f7eb2Smrg copy = contained->proc_name;
2822627f7eb2Smrg goto got_char_copy;
2823627f7eb2Smrg }
2824627f7eb2Smrg }
2825627f7eb2Smrg
2826627f7eb2Smrg /* Set up namespace. */
2827627f7eb2Smrg sub_ns = gfc_get_namespace (ns, 0);
2828627f7eb2Smrg sub_ns->sibling = ns->contained;
2829627f7eb2Smrg ns->contained = sub_ns;
2830627f7eb2Smrg sub_ns->resolved = 1;
2831627f7eb2Smrg /* Set up procedure symbol. */
2832627f7eb2Smrg gfc_get_symbol (name, sub_ns, ©);
2833627f7eb2Smrg sub_ns->proc_name = copy;
2834627f7eb2Smrg copy->attr.flavor = FL_PROCEDURE;
2835627f7eb2Smrg copy->attr.subroutine = 1;
2836627f7eb2Smrg copy->attr.pure = 1;
2837627f7eb2Smrg copy->attr.if_source = IFSRC_DECL;
2838627f7eb2Smrg /* This is elemental so that arrays are automatically
2839627f7eb2Smrg treated correctly by the scalarizer. */
2840627f7eb2Smrg copy->attr.elemental = 1;
2841627f7eb2Smrg if (ns->proc_name && ns->proc_name->attr.flavor == FL_MODULE)
2842627f7eb2Smrg copy->module = ns->proc_name->name;
2843627f7eb2Smrg gfc_set_sym_referenced (copy);
2844627f7eb2Smrg /* Set up formal arguments. */
2845627f7eb2Smrg gfc_get_symbol ("src", sub_ns, &src);
2846627f7eb2Smrg src->ts.type = ts->type;
2847627f7eb2Smrg src->ts.kind = ts->kind;
2848627f7eb2Smrg src->attr.flavor = FL_VARIABLE;
2849627f7eb2Smrg src->attr.dummy = 1;
2850627f7eb2Smrg src->attr.intent = INTENT_IN;
2851627f7eb2Smrg gfc_set_sym_referenced (src);
2852627f7eb2Smrg copy->formal = gfc_get_formal_arglist ();
2853627f7eb2Smrg copy->formal->sym = src;
2854627f7eb2Smrg gfc_get_symbol ("dst", sub_ns, &dst);
2855627f7eb2Smrg dst->ts.type = ts->type;
2856627f7eb2Smrg dst->ts.kind = ts->kind;
2857627f7eb2Smrg dst->attr.flavor = FL_VARIABLE;
2858627f7eb2Smrg dst->attr.dummy = 1;
2859627f7eb2Smrg dst->attr.intent = INTENT_INOUT;
2860627f7eb2Smrg gfc_set_sym_referenced (dst);
2861627f7eb2Smrg copy->formal->next = gfc_get_formal_arglist ();
2862627f7eb2Smrg copy->formal->next->sym = dst;
2863627f7eb2Smrg /* Set up code. */
2864627f7eb2Smrg sub_ns->code = gfc_get_code (EXEC_INIT_ASSIGN);
2865627f7eb2Smrg sub_ns->code->expr1 = gfc_lval_expr_from_sym (dst);
2866627f7eb2Smrg sub_ns->code->expr2 = gfc_lval_expr_from_sym (src);
2867627f7eb2Smrg got_char_copy:
2868627f7eb2Smrg /* Set initializer. */
2869627f7eb2Smrg c->initializer = gfc_lval_expr_from_sym (copy);
2870627f7eb2Smrg c->ts.interface = copy;
2871627f7eb2Smrg
2872627f7eb2Smrg /* Add component _final. */
2873627f7eb2Smrg if (!gfc_add_component (vtype, "_final", &c))
2874627f7eb2Smrg goto cleanup;
2875627f7eb2Smrg c->attr.proc_pointer = 1;
2876627f7eb2Smrg c->attr.access = ACCESS_PRIVATE;
2877627f7eb2Smrg c->attr.artificial = 1;
2878627f7eb2Smrg c->tb = XCNEW (gfc_typebound_proc);
2879627f7eb2Smrg c->tb->ppc = 1;
2880627f7eb2Smrg c->initializer = gfc_get_null_expr (NULL);
2881627f7eb2Smrg }
2882627f7eb2Smrg vtab->ts.u.derived = vtype;
2883627f7eb2Smrg vtab->value = gfc_default_initializer (&vtab->ts);
2884627f7eb2Smrg }
2885627f7eb2Smrg free (name);
2886627f7eb2Smrg }
2887627f7eb2Smrg
2888627f7eb2Smrg found_sym = vtab;
2889627f7eb2Smrg
2890627f7eb2Smrg cleanup:
2891627f7eb2Smrg /* It is unexpected to have some symbols added at resolution or code
2892627f7eb2Smrg generation time. We commit the changes in order to keep a clean state. */
2893627f7eb2Smrg if (found_sym)
2894627f7eb2Smrg {
2895627f7eb2Smrg gfc_commit_symbol (vtab);
2896627f7eb2Smrg if (vtype)
2897627f7eb2Smrg gfc_commit_symbol (vtype);
2898627f7eb2Smrg if (copy)
2899627f7eb2Smrg gfc_commit_symbol (copy);
2900627f7eb2Smrg if (src)
2901627f7eb2Smrg gfc_commit_symbol (src);
2902627f7eb2Smrg if (dst)
2903627f7eb2Smrg gfc_commit_symbol (dst);
2904627f7eb2Smrg }
2905627f7eb2Smrg else
2906627f7eb2Smrg gfc_undo_symbols ();
2907627f7eb2Smrg
2908627f7eb2Smrg return found_sym;
2909627f7eb2Smrg }
2910627f7eb2Smrg
2911627f7eb2Smrg
2912627f7eb2Smrg /* Find (or generate) a vtab for an arbitrary type (derived or intrinsic). */
2913627f7eb2Smrg
2914627f7eb2Smrg gfc_symbol *
gfc_find_vtab(gfc_typespec * ts)2915627f7eb2Smrg gfc_find_vtab (gfc_typespec *ts)
2916627f7eb2Smrg {
2917627f7eb2Smrg switch (ts->type)
2918627f7eb2Smrg {
2919627f7eb2Smrg case BT_UNKNOWN:
2920627f7eb2Smrg return NULL;
2921627f7eb2Smrg case BT_DERIVED:
2922627f7eb2Smrg return gfc_find_derived_vtab (ts->u.derived);
2923627f7eb2Smrg case BT_CLASS:
2924*4c3eb207Smrg if (ts->u.derived->attr.is_class
2925*4c3eb207Smrg && ts->u.derived->components
2926*4c3eb207Smrg && ts->u.derived->components->ts.u.derived)
2927627f7eb2Smrg return gfc_find_derived_vtab (ts->u.derived->components->ts.u.derived);
2928627f7eb2Smrg else
2929627f7eb2Smrg return NULL;
2930627f7eb2Smrg default:
2931627f7eb2Smrg return find_intrinsic_vtab (ts);
2932627f7eb2Smrg }
2933627f7eb2Smrg }
2934627f7eb2Smrg
2935627f7eb2Smrg
2936627f7eb2Smrg /* General worker function to find either a type-bound procedure or a
2937627f7eb2Smrg type-bound user operator. */
2938627f7eb2Smrg
2939627f7eb2Smrg static gfc_symtree*
find_typebound_proc_uop(gfc_symbol * derived,bool * t,const char * name,bool noaccess,bool uop,locus * where)2940627f7eb2Smrg find_typebound_proc_uop (gfc_symbol* derived, bool* t,
2941627f7eb2Smrg const char* name, bool noaccess, bool uop,
2942627f7eb2Smrg locus* where)
2943627f7eb2Smrg {
2944627f7eb2Smrg gfc_symtree* res;
2945627f7eb2Smrg gfc_symtree* root;
2946627f7eb2Smrg
2947627f7eb2Smrg /* Set default to failure. */
2948627f7eb2Smrg if (t)
2949627f7eb2Smrg *t = false;
2950627f7eb2Smrg
2951627f7eb2Smrg if (derived->f2k_derived)
2952627f7eb2Smrg /* Set correct symbol-root. */
2953627f7eb2Smrg root = (uop ? derived->f2k_derived->tb_uop_root
2954627f7eb2Smrg : derived->f2k_derived->tb_sym_root);
2955627f7eb2Smrg else
2956627f7eb2Smrg return NULL;
2957627f7eb2Smrg
2958627f7eb2Smrg /* Try to find it in the current type's namespace. */
2959627f7eb2Smrg res = gfc_find_symtree (root, name);
2960627f7eb2Smrg if (res && res->n.tb && !res->n.tb->error)
2961627f7eb2Smrg {
2962627f7eb2Smrg /* We found one. */
2963627f7eb2Smrg if (t)
2964627f7eb2Smrg *t = true;
2965627f7eb2Smrg
2966627f7eb2Smrg if (!noaccess && derived->attr.use_assoc
2967627f7eb2Smrg && res->n.tb->access == ACCESS_PRIVATE)
2968627f7eb2Smrg {
2969627f7eb2Smrg if (where)
2970627f7eb2Smrg gfc_error ("%qs of %qs is PRIVATE at %L",
2971627f7eb2Smrg name, derived->name, where);
2972627f7eb2Smrg if (t)
2973627f7eb2Smrg *t = false;
2974627f7eb2Smrg }
2975627f7eb2Smrg
2976627f7eb2Smrg return res;
2977627f7eb2Smrg }
2978627f7eb2Smrg
2979627f7eb2Smrg /* Otherwise, recurse on parent type if derived is an extension. */
2980627f7eb2Smrg if (derived->attr.extension)
2981627f7eb2Smrg {
2982627f7eb2Smrg gfc_symbol* super_type;
2983627f7eb2Smrg super_type = gfc_get_derived_super_type (derived);
2984627f7eb2Smrg gcc_assert (super_type);
2985627f7eb2Smrg
2986627f7eb2Smrg return find_typebound_proc_uop (super_type, t, name,
2987627f7eb2Smrg noaccess, uop, where);
2988627f7eb2Smrg }
2989627f7eb2Smrg
2990627f7eb2Smrg /* Nothing found. */
2991627f7eb2Smrg return NULL;
2992627f7eb2Smrg }
2993627f7eb2Smrg
2994627f7eb2Smrg
2995627f7eb2Smrg /* Find a type-bound procedure or user operator by name for a derived-type
2996627f7eb2Smrg (looking recursively through the super-types). */
2997627f7eb2Smrg
2998627f7eb2Smrg gfc_symtree*
gfc_find_typebound_proc(gfc_symbol * derived,bool * t,const char * name,bool noaccess,locus * where)2999627f7eb2Smrg gfc_find_typebound_proc (gfc_symbol* derived, bool* t,
3000627f7eb2Smrg const char* name, bool noaccess, locus* where)
3001627f7eb2Smrg {
3002627f7eb2Smrg return find_typebound_proc_uop (derived, t, name, noaccess, false, where);
3003627f7eb2Smrg }
3004627f7eb2Smrg
3005627f7eb2Smrg gfc_symtree*
gfc_find_typebound_user_op(gfc_symbol * derived,bool * t,const char * name,bool noaccess,locus * where)3006627f7eb2Smrg gfc_find_typebound_user_op (gfc_symbol* derived, bool* t,
3007627f7eb2Smrg const char* name, bool noaccess, locus* where)
3008627f7eb2Smrg {
3009627f7eb2Smrg return find_typebound_proc_uop (derived, t, name, noaccess, true, where);
3010627f7eb2Smrg }
3011627f7eb2Smrg
3012627f7eb2Smrg
3013627f7eb2Smrg /* Find a type-bound intrinsic operator looking recursively through the
3014627f7eb2Smrg super-type hierarchy. */
3015627f7eb2Smrg
3016627f7eb2Smrg gfc_typebound_proc*
gfc_find_typebound_intrinsic_op(gfc_symbol * derived,bool * t,gfc_intrinsic_op op,bool noaccess,locus * where)3017627f7eb2Smrg gfc_find_typebound_intrinsic_op (gfc_symbol* derived, bool* t,
3018627f7eb2Smrg gfc_intrinsic_op op, bool noaccess,
3019627f7eb2Smrg locus* where)
3020627f7eb2Smrg {
3021627f7eb2Smrg gfc_typebound_proc* res;
3022627f7eb2Smrg
3023627f7eb2Smrg /* Set default to failure. */
3024627f7eb2Smrg if (t)
3025627f7eb2Smrg *t = false;
3026627f7eb2Smrg
3027627f7eb2Smrg /* Try to find it in the current type's namespace. */
3028627f7eb2Smrg if (derived->f2k_derived)
3029627f7eb2Smrg res = derived->f2k_derived->tb_op[op];
3030627f7eb2Smrg else
3031627f7eb2Smrg res = NULL;
3032627f7eb2Smrg
3033627f7eb2Smrg /* Check access. */
3034627f7eb2Smrg if (res && !res->error)
3035627f7eb2Smrg {
3036627f7eb2Smrg /* We found one. */
3037627f7eb2Smrg if (t)
3038627f7eb2Smrg *t = true;
3039627f7eb2Smrg
3040627f7eb2Smrg if (!noaccess && derived->attr.use_assoc
3041627f7eb2Smrg && res->access == ACCESS_PRIVATE)
3042627f7eb2Smrg {
3043627f7eb2Smrg if (where)
3044627f7eb2Smrg gfc_error ("%qs of %qs is PRIVATE at %L",
3045627f7eb2Smrg gfc_op2string (op), derived->name, where);
3046627f7eb2Smrg if (t)
3047627f7eb2Smrg *t = false;
3048627f7eb2Smrg }
3049627f7eb2Smrg
3050627f7eb2Smrg return res;
3051627f7eb2Smrg }
3052627f7eb2Smrg
3053627f7eb2Smrg /* Otherwise, recurse on parent type if derived is an extension. */
3054627f7eb2Smrg if (derived->attr.extension)
3055627f7eb2Smrg {
3056627f7eb2Smrg gfc_symbol* super_type;
3057627f7eb2Smrg super_type = gfc_get_derived_super_type (derived);
3058627f7eb2Smrg gcc_assert (super_type);
3059627f7eb2Smrg
3060627f7eb2Smrg return gfc_find_typebound_intrinsic_op (super_type, t, op,
3061627f7eb2Smrg noaccess, where);
3062627f7eb2Smrg }
3063627f7eb2Smrg
3064627f7eb2Smrg /* Nothing found. */
3065627f7eb2Smrg return NULL;
3066627f7eb2Smrg }
3067627f7eb2Smrg
3068627f7eb2Smrg
3069627f7eb2Smrg /* Get a typebound-procedure symtree or create and insert it if not yet
3070627f7eb2Smrg present. This is like a very simplified version of gfc_get_sym_tree for
3071627f7eb2Smrg tbp-symtrees rather than regular ones. */
3072627f7eb2Smrg
3073627f7eb2Smrg gfc_symtree*
gfc_get_tbp_symtree(gfc_symtree ** root,const char * name)3074627f7eb2Smrg gfc_get_tbp_symtree (gfc_symtree **root, const char *name)
3075627f7eb2Smrg {
3076627f7eb2Smrg gfc_symtree *result = gfc_find_symtree (*root, name);
3077627f7eb2Smrg return result ? result : gfc_new_symtree (root, name);
3078627f7eb2Smrg }
3079