aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/symbol.c')
-rw-r--r--gcc/fortran/symbol.c159
1 files changed, 134 insertions, 25 deletions
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index 8efd12c..0ee7dec 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -40,6 +40,7 @@ const mstring flavors[] =
minit ("VARIABLE", FL_VARIABLE), minit ("PARAMETER", FL_PARAMETER),
minit ("LABEL", FL_LABEL), minit ("PROCEDURE", FL_PROCEDURE),
minit ("DERIVED", FL_DERIVED), minit ("NAMELIST", FL_NAMELIST),
+ minit ("UNION", FL_UNION), minit ("STRUCTURE", FL_STRUCT),
minit (NULL, -1)
};
@@ -444,7 +445,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
case FL_BLOCK_DATA:
case FL_MODULE:
case FL_LABEL:
- case FL_DERIVED:
+ case_fl_struct:
case FL_PARAMETER:
a1 = gfc_code2string (flavors, attr->flavor);
a2 = save;
@@ -740,7 +741,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
break;
- case FL_DERIVED:
+ case_fl_struct:
conf2 (dummy);
conf2 (pointer);
conf2 (target);
@@ -1579,7 +1580,7 @@ gfc_add_flavor (symbol_attribute *attr, sym_flavor f, const char *name,
{
if ((f == FL_PROGRAM || f == FL_BLOCK_DATA || f == FL_MODULE
- || f == FL_PARAMETER || f == FL_LABEL || f == FL_DERIVED
+ || f == FL_PARAMETER || f == FL_LABEL || gfc_fl_struct(f)
|| f == FL_NAMELIST) && check_used (attr, name, where))
return false;
@@ -2048,6 +2049,11 @@ gfc_add_component (gfc_symbol *sym, const char *name,
{
gfc_component *p, *tail;
+ /* Check for existing components with the same name, but not for union
+ components or containers. Unions and maps are anonymous so they have
+ unique internal names which will never conflict.
+ Don't use gfc_find_component here because it calls gfc_use_derived,
+ but the derived type may not be fully defined yet. */
tail = NULL;
for (p = sym->components; p; p = p->next)
@@ -2063,7 +2069,8 @@ gfc_add_component (gfc_symbol *sym, const char *name,
}
if (sym->attr.extension
- && gfc_find_component (sym->components->ts.u.derived, name, true, true))
+ && gfc_find_component (sym->components->ts.u.derived,
+ name, true, true, NULL))
{
gfc_error ("Component %qs at %C already in the parent type "
"at %L", name, &sym->components->ts.u.derived->declared_at);
@@ -2154,7 +2161,7 @@ gfc_use_derived (gfc_symbol *sym)
return NULL;
}
- if (s == NULL || s->attr.flavor != FL_DERIVED)
+ if (s == NULL || !gfc_fl_struct (s->attr.flavor))
goto bad;
/* Get rid of symbol sym, translating all references to s. */
@@ -2188,28 +2195,113 @@ bad:
}
+/* Find the component with the given name in the union type symbol.
+ If ref is not NULL it will be set to the chain of components through which
+ the component can actually be accessed. This is necessary for unions because
+ intermediate structures may be maps, nested structures, or other unions,
+ all of which may (or must) be 'anonymous' to user code. */
+
+static gfc_component *
+find_union_component (gfc_symbol *un, const char *name,
+ bool noaccess, gfc_ref **ref)
+{
+ gfc_component *m, *check;
+ gfc_ref *sref, *tmp;
+
+ for (m = un->components; m; m = m->next)
+ {
+ check = gfc_find_component (m->ts.u.derived, name, noaccess, true, &tmp);
+ if (check == NULL)
+ continue;
+
+ /* Found component somewhere in m; chain the refs together. */
+ if (ref)
+ {
+ /* Map ref. */
+ sref = gfc_get_ref ();
+ sref->type = REF_COMPONENT;
+ sref->u.c.component = m;
+ sref->u.c.sym = m->ts.u.derived;
+ sref->next = tmp;
+
+ *ref = sref;
+ }
+ /* Other checks (such as access) were done in the recursive calls. */
+ return check;
+ }
+ return NULL;
+}
+
+
/* Given a derived type node and a component name, try to locate the
component structure. Returns the NULL pointer if the component is
not found or the components are private. If noaccess is set, no access
- checks are done. */
+ checks are done. If silent is set, an error will not be generated if
+ the component cannot be found or accessed.
+
+ If ref is not NULL, *ref is set to represent the chain of components
+ required to get to the ultimate component.
+
+ If the component is simply a direct subcomponent, or is inherited from a
+ parent derived type in the given derived type, this is a single ref with its
+ component set to the returned component.
+
+ Otherwise, *ref is constructed as a chain of subcomponents. This occurs
+ when the component is found through an implicit chain of nested union and
+ map components. Unions and maps are "anonymous" substructures in FORTRAN
+ which cannot be explicitly referenced, but the reference chain must be
+ considered as in C for backend translation to correctly compute layouts.
+ (For example, x.a may refer to x->(UNION)->(MAP)->(UNION)->(MAP)->a). */
gfc_component *
gfc_find_component (gfc_symbol *sym, const char *name,
- bool noaccess, bool silent)
+ bool noaccess, bool silent, gfc_ref **ref)
{
- gfc_component *p;
+ gfc_component *p, *check;
+ gfc_ref *sref = NULL, *tmp = NULL;
if (name == NULL || sym == NULL)
return NULL;
- sym = gfc_use_derived (sym);
+ if (sym->attr.flavor == FL_DERIVED)
+ sym = gfc_use_derived (sym);
+ else
+ gcc_assert (gfc_fl_struct (sym->attr.flavor));
if (sym == NULL)
return NULL;
+ /* Handle UNIONs specially - mutually recursive with gfc_find_component. */
+ if (sym->attr.flavor == FL_UNION)
+ return find_union_component (sym, name, noaccess, ref);
+
+ if (ref) *ref = NULL;
for (p = sym->components; p; p = p->next)
- if (strcmp (p->name, name) == 0)
- break;
+ {
+ /* Nest search into union's maps. */
+ if (p->ts.type == BT_UNION)
+ {
+ check = find_union_component (p->ts.u.derived, name, noaccess, &tmp);
+ if (check != NULL)
+ {
+ /* Union ref. */
+ if (ref)
+ {
+ sref = gfc_get_ref ();
+ sref->type = REF_COMPONENT;
+ sref->u.c.component = p;
+ sref->u.c.sym = p->ts.u.derived;
+ sref->next = tmp;
+ *ref = sref;
+ }
+ return check;
+ }
+ }
+ else if (strcmp (p->name, name) == 0)
+ break;
+
+ continue;
+ }
if (p && sym->attr.use_assoc && !noaccess)
{
@@ -2231,7 +2323,7 @@ gfc_find_component (gfc_symbol *sym, const char *name,
&& sym->components->ts.type == BT_DERIVED)
{
p = gfc_find_component (sym->components->ts.u.derived, name,
- noaccess, silent);
+ noaccess, silent, ref);
/* Do not overwrite the error. */
if (p == NULL)
return p;
@@ -2241,6 +2333,25 @@ gfc_find_component (gfc_symbol *sym, const char *name,
gfc_error ("%qs at %C is not a member of the %qs structure",
name, sym->name);
+ /* Component was found; build the ultimate component reference. */
+ if (p != NULL && ref)
+ {
+ tmp = gfc_get_ref ();
+ tmp->type = REF_COMPONENT;
+ tmp->u.c.component = p;
+ tmp->u.c.sym = sym;
+ /* Link the final component ref to the end of the chain of subrefs. */
+ if (sref)
+ {
+ *ref = sref;
+ for (; sref->next; sref = sref->next)
+ ;
+ sref->next = tmp;
+ }
+ else
+ *ref = tmp;
+ }
+
return p;
}
@@ -3338,11 +3449,9 @@ gfc_restore_last_undo_checkpoint (void)
/* The derived type is saved in the symtree with the first
letter capitalized; the all lower-case version to the
derived type contains its associated generic function. */
- if (p->attr.flavor == FL_DERIVED)
- gfc_delete_symtree (&p->ns->sym_root, gfc_get_string ("%c%s",
- (char) TOUPPER ((unsigned char) p->name[0]),
- &p->name[1]));
- else
+ if (gfc_fl_struct (p->attr.flavor))
+ gfc_delete_symtree (&p->ns->sym_root,gfc_dt_upper_string (p->name));
+ else
gfc_delete_symtree (&p->ns->sym_root, p->name);
gfc_release_symbol (p);
@@ -4526,10 +4635,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
const char *hidden_name;
gfc_interface *intr, *head;
- hidden_name = gfc_get_string ("%c%s",
- (char) TOUPPER ((unsigned char)
- tmp_sym->name[0]),
- &tmp_sym->name[1]);
+ hidden_name = gfc_dt_upper_string (tmp_sym->name);
tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root,
hidden_name);
gcc_assert (tmp_symtree == NULL);
@@ -4740,6 +4846,8 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2)
bool is_class2 = (ts2->type == BT_CLASS);
bool is_derived1 = (ts1->type == BT_DERIVED);
bool is_derived2 = (ts2->type == BT_DERIVED);
+ bool is_union1 = (ts1->type == BT_UNION);
+ bool is_union2 = (ts2->type == BT_UNION);
if (is_class1
&& ts1->u.derived->components
@@ -4749,10 +4857,11 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2)
|| ts1->u.derived->attr.unlimited_polymorphic))
return 1;
- if (!is_derived1 && !is_derived2 && !is_class1 && !is_class2)
+ if (!is_derived1 && !is_derived2 && !is_class1 && !is_class2
+ && !is_union1 && !is_union2)
return (ts1->type == ts2->type);
- if (is_derived1 && is_derived2)
+ if ((is_derived1 && is_derived2) || (is_union1 && is_union1))
return gfc_compare_derived_types (ts1->u.derived, ts2->u.derived);
if (is_derived1 && is_class2)
@@ -4821,12 +4930,12 @@ gfc_find_dt_in_generic (gfc_symbol *sym)
{
gfc_interface *intr = NULL;
- if (!sym || sym->attr.flavor == FL_DERIVED)
+ if (!sym || gfc_fl_struct (sym->attr.flavor))
return sym;
if (sym->attr.generic)
for (intr = sym->generic; intr; intr = intr->next)
- if (intr->sym->attr.flavor == FL_DERIVED)
+ if (gfc_fl_struct (intr->sym->attr.flavor))
break;
return intr ? intr->sym : NULL;
}