xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/fortran/class.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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, &copy);
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, &copy);
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