| Index: gcc/gcc/fortran/symbol.c
|
| diff --git a/gcc/gcc/fortran/symbol.c b/gcc/gcc/fortran/symbol.c
|
| index 6a82d1055db30c59598bce934db164eb864ebeb8..98af7550f2241c362f3b7a50cef39a7f55981538 100644
|
| --- a/gcc/gcc/fortran/symbol.c
|
| +++ b/gcc/gcc/fortran/symbol.c
|
| @@ -1,5 +1,6 @@
|
| /* Maintain binary trees of symbols.
|
| - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
| + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
| + 2009, 2010
|
| Free Software Foundation, Inc.
|
| Contributed by Andy Vaught
|
|
|
| @@ -75,8 +76,7 @@ const mstring ifsrc_types[] =
|
| {
|
| minit ("UNKNOWN", IFSRC_UNKNOWN),
|
| minit ("DECL", IFSRC_DECL),
|
| - minit ("BODY", IFSRC_IFBODY),
|
| - minit ("USAGE", IFSRC_USAGE)
|
| + minit ("BODY", IFSRC_IFBODY)
|
| };
|
|
|
| const mstring save_status[] =
|
| @@ -93,6 +93,7 @@ static int next_dummy_order = 1;
|
|
|
|
|
| gfc_namespace *gfc_current_ns;
|
| +gfc_namespace *gfc_global_ns_list;
|
|
|
| gfc_gsymbol *gfc_gsym_root = NULL;
|
|
|
| @@ -101,6 +102,18 @@ static gfc_symbol *changed_syms = NULL;
|
| gfc_dt_list *gfc_derived_types;
|
|
|
|
|
| +/* List of tentative typebound-procedures. */
|
| +
|
| +typedef struct tentative_tbp
|
| +{
|
| + gfc_typebound_proc *proc;
|
| + struct tentative_tbp *next;
|
| +}
|
| +tentative_tbp;
|
| +
|
| +static tentative_tbp *tentative_tbp_list = NULL;
|
| +
|
| +
|
| /*********** IMPLICIT NONE and IMPLICIT statement handlers ***********/
|
|
|
| /* The following static variable indicates whether a particular element has
|
| @@ -207,11 +220,11 @@ gfc_merge_new_implicit (gfc_typespec *ts)
|
| /* Given a symbol, return a pointer to the typespec for its default type. */
|
|
|
| gfc_typespec *
|
| -gfc_get_default_type (gfc_symbol *sym, gfc_namespace *ns)
|
| +gfc_get_default_type (const char *name, gfc_namespace *ns)
|
| {
|
| char letter;
|
|
|
| - letter = sym->name[0];
|
| + letter = name[0];
|
|
|
| if (gfc_option.flag_allow_leading_underscore && letter == '_')
|
| gfc_internal_error ("Option -fallow-leading-underscore is for use only by "
|
| @@ -219,7 +232,7 @@ gfc_get_default_type (gfc_symbol *sym, gfc_namespace *ns)
|
| "implicitly typed variables");
|
|
|
| if (letter < 'a' || letter > 'z')
|
| - gfc_internal_error ("gfc_get_default_type(): Bad symbol '%s'",sym->name);
|
| + gfc_internal_error ("gfc_get_default_type(): Bad symbol '%s'", name);
|
|
|
| if (ns == NULL)
|
| ns = gfc_current_ns;
|
| @@ -240,7 +253,7 @@ gfc_set_default_type (gfc_symbol *sym, int error_flag, gfc_namespace *ns)
|
| if (sym->ts.type != BT_UNKNOWN)
|
| gfc_internal_error ("gfc_set_default_type(): symbol already has a type");
|
|
|
| - ts = gfc_get_default_type (sym, ns);
|
| + ts = gfc_get_default_type (sym->name, ns);
|
|
|
| if (ts->type == BT_UNKNOWN)
|
| {
|
| @@ -257,11 +270,8 @@ gfc_set_default_type (gfc_symbol *sym, int error_flag, gfc_namespace *ns)
|
| sym->ts = *ts;
|
| sym->attr.implicit_type = 1;
|
|
|
| - if (ts->cl)
|
| - {
|
| - sym->ts.cl = gfc_get_charlen ();
|
| - *sym->ts.cl = *ts->cl;
|
| - }
|
| + if (ts->type == BT_CHARACTER && ts->u.cl)
|
| + sym->ts.u.cl = gfc_new_charlen (sym->ns, ts->u.cl);
|
|
|
| if (sym->attr.is_bind_c == 1)
|
| {
|
| @@ -305,7 +315,7 @@ gfc_check_function_type (gfc_namespace *ns)
|
| if (!proc->attr.contained || proc->result->attr.implicit_type)
|
| return;
|
|
|
| - if (proc->result->ts.type == BT_UNKNOWN)
|
| + if (proc->result->ts.type == BT_UNKNOWN && proc->result->ts.interface == NULL)
|
| {
|
| if (gfc_set_default_type (proc->result, 0, gfc_current_ns)
|
| == SUCCESS)
|
| @@ -319,7 +329,7 @@ gfc_check_function_type (gfc_namespace *ns)
|
| proc->attr.allocatable = proc->result->attr.allocatable;
|
| }
|
| }
|
| - else
|
| + else if (!proc->result->attr.proc_pointer)
|
| {
|
| gfc_error ("Function result '%s' at %L has no IMPLICIT type",
|
| proc->result->name, &proc->result->declared_at);
|
| @@ -360,7 +370,8 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| *use_assoc = "USE ASSOCIATED", *cray_pointer = "CRAY POINTER",
|
| *cray_pointee = "CRAY POINTEE", *data = "DATA", *value = "VALUE",
|
| *volatile_ = "VOLATILE", *is_protected = "PROTECTED",
|
| - *is_bind_c = "BIND(C)", *procedure = "PROCEDURE";
|
| + *is_bind_c = "BIND(C)", *procedure = "PROCEDURE",
|
| + *asynchronous = "ASYNCHRONOUS";
|
| static const char *threadprivate = "THREADPRIVATE";
|
|
|
| const char *a1, *a2;
|
| @@ -452,10 +463,11 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| conf (entry, intrinsic);
|
|
|
| if ((attr->if_source == IFSRC_DECL && !attr->procedure) || attr->contained)
|
| - {
|
| - conf (external, subroutine);
|
| - conf (external, function);
|
| - }
|
| + conf (external, subroutine);
|
| +
|
| + if (attr->proc_pointer && gfc_notify_std (GFC_STD_F2003,
|
| + "Fortran 2003: Procedure pointer at %C") == FAILURE)
|
| + return FAILURE;
|
|
|
| conf (allocatable, pointer);
|
| conf_std (allocatable, dummy, GFC_STD_F2003);
|
| @@ -549,6 +561,9 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| conf (is_protected, external)
|
| conf (is_protected, in_common)
|
|
|
| + conf (asynchronous, intrinsic)
|
| + conf (asynchronous, external)
|
| +
|
| conf (volatile_, intrinsic)
|
| conf (volatile_, external)
|
|
|
| @@ -566,6 +581,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| conf (procedure, target)
|
| conf (procedure, value)
|
| conf (procedure, volatile_)
|
| + conf (procedure, asynchronous)
|
| conf (procedure, entry)
|
|
|
| a1 = gfc_code2string (flavors, attr->flavor);
|
| @@ -588,6 +604,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| conf2 (dimension);
|
| conf2 (dummy);
|
| conf2 (volatile_);
|
| + conf2 (asynchronous);
|
| conf2 (pointer);
|
| conf2 (is_protected);
|
| conf2 (target);
|
| @@ -625,14 +642,16 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| break;
|
|
|
| case FL_PROCEDURE:
|
| - /* Conflicts with INTENT will be checked at resolution stage,
|
| - see "resolve_fl_procedure". */
|
| + /* Conflicts with INTENT, SAVE and RESULT will be checked
|
| + at resolution stage, see "resolve_fl_procedure". */
|
|
|
| if (attr->subroutine)
|
| {
|
| + a1 = subroutine;
|
| conf2 (target);
|
| conf2 (allocatable);
|
| - conf2 (result);
|
| + conf2 (volatile_);
|
| + conf2 (asynchronous);
|
| conf2 (in_namelist);
|
| conf2 (dimension);
|
| conf2 (function);
|
| @@ -699,6 +718,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
|
| conf2 (in_common);
|
| conf2 (value);
|
| conf2 (volatile_);
|
| + conf2 (asynchronous);
|
| conf2 (threadprivate);
|
| conf2 (value);
|
| conf2 (is_bind_c);
|
| @@ -797,19 +817,28 @@ duplicate_attr (const char *attr, locus *where)
|
| }
|
|
|
|
|
| +gfc_try
|
| +gfc_add_ext_attribute (symbol_attribute *attr, ext_attr_id_t ext_attr,
|
| + locus *where ATTRIBUTE_UNUSED)
|
| +{
|
| + attr->ext_attr |= 1 << ext_attr;
|
| + return SUCCESS;
|
| +}
|
| +
|
| +
|
| /* Called from decl.c (attr_decl1) to check attributes, when declared
|
| separately. */
|
|
|
| gfc_try
|
| gfc_add_attribute (symbol_attribute *attr, locus *where)
|
| {
|
| -
|
| if (check_used (attr, NULL, where))
|
| return FAILURE;
|
|
|
| return check_conflict (attr, NULL, where);
|
| }
|
|
|
| +
|
| gfc_try
|
| gfc_add_allocatable (symbol_attribute *attr, locus *where)
|
| {
|
| @@ -1027,7 +1056,7 @@ gfc_add_save (symbol_attribute *attr, const char *name, locus *where)
|
| return FAILURE;
|
| }
|
|
|
| - if (attr->save == SAVE_EXPLICIT)
|
| + if (attr->save == SAVE_EXPLICIT && !attr->vtab)
|
| {
|
| if (gfc_notify_std (GFC_STD_LEGACY,
|
| "Duplicate SAVE attribute specified at %L",
|
| @@ -1082,6 +1111,25 @@ gfc_add_volatile (symbol_attribute *attr, const char *name, locus *where)
|
|
|
|
|
| gfc_try
|
| +gfc_add_asynchronous (symbol_attribute *attr, const char *name, locus *where)
|
| +{
|
| + /* No check_used needed as 11.2.1 of the F2003 standard allows
|
| + that the local identifier made accessible by a use statement can be
|
| + given a ASYNCHRONOUS attribute. */
|
| +
|
| + if (attr->asynchronous && attr->asynchronous_ns == gfc_current_ns)
|
| + if (gfc_notify_std (GFC_STD_LEGACY,
|
| + "Duplicate ASYNCHRONOUS attribute specified at %L",
|
| + where) == FAILURE)
|
| + return FAILURE;
|
| +
|
| + attr->asynchronous = 1;
|
| + attr->asynchronous_ns = gfc_current_ns;
|
| + return check_conflict (attr, name, where);
|
| +}
|
| +
|
| +
|
| +gfc_try
|
| gfc_add_threadprivate (symbol_attribute *attr, const char *name, locus *where)
|
| {
|
|
|
| @@ -1547,26 +1595,31 @@ gfc_try
|
| gfc_add_type (gfc_symbol *sym, gfc_typespec *ts, locus *where)
|
| {
|
| sym_flavor flavor;
|
| + bt type;
|
|
|
| if (where == NULL)
|
| where = &gfc_current_locus;
|
|
|
| - if (sym->ts.type != BT_UNKNOWN)
|
| + if (sym->result)
|
| + type = sym->result->ts.type;
|
| + else
|
| + type = sym->ts.type;
|
| +
|
| + if (sym->attr.result && type == BT_UNKNOWN && sym->ns->proc_name)
|
| + type = sym->ns->proc_name->ts.type;
|
| +
|
| + if (type != BT_UNKNOWN && !(sym->attr.function && sym->attr.implicit_type))
|
| {
|
| - const char *msg = "Symbol '%s' at %L already has basic type of %s";
|
| - if (!(sym->ts.type == ts->type
|
| - && (sym->attr.flavor == FL_PROCEDURE || sym->attr.result))
|
| - || gfc_notification_std (GFC_STD_GNU) == ERROR
|
| - || pedantic)
|
| - {
|
| - gfc_error (msg, sym->name, where, gfc_basic_typename (sym->ts.type));
|
| - return FAILURE;
|
| - }
|
| - if (gfc_notify_std (GFC_STD_GNU, msg, sym->name, where,
|
| - gfc_basic_typename (sym->ts.type)) == FAILURE)
|
| - return FAILURE;
|
| - if (gfc_option.warn_surprising)
|
| - gfc_warning (msg, sym->name, where, gfc_basic_typename (sym->ts.type));
|
| + gfc_error ("Symbol '%s' at %L already has basic type of %s", sym->name,
|
| + where, gfc_basic_typename (type));
|
| + return FAILURE;
|
| + }
|
| +
|
| + if (sym->attr.procedure && sym->ts.interface)
|
| + {
|
| + gfc_error ("Procedure '%s' at %L may not have basic type of %s",
|
| + sym->name, where, gfc_basic_typename (ts->type));
|
| + return FAILURE;
|
| }
|
|
|
| flavor = sym->attr.flavor;
|
| @@ -1615,6 +1668,10 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
|
| {
|
| int is_proc_lang_bind_spec;
|
|
|
| + /* In line with the other attributes, we only add bits but do not remove
|
| + them; cf. also PR 41034. */
|
| + dest->ext_attr |= src->ext_attr;
|
| +
|
| if (src->allocatable && gfc_add_allocatable (dest, where) == FAILURE)
|
| goto fail;
|
|
|
| @@ -1632,6 +1689,8 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
|
| goto fail;
|
| if (src->volatile_ && gfc_add_volatile (dest, NULL, where) == FAILURE)
|
| goto fail;
|
| + if (src->asynchronous && gfc_add_asynchronous (dest, NULL, where) == FAILURE)
|
| + goto fail;
|
| if (src->threadprivate
|
| && gfc_add_threadprivate (dest, NULL, where) == FAILURE)
|
| goto fail;
|
| @@ -1684,7 +1743,7 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
|
| if (src->cray_pointer && gfc_add_cray_pointer (dest, where) == FAILURE)
|
| goto fail;
|
| if (src->cray_pointee && gfc_add_cray_pointee (dest, where) == FAILURE)
|
| - goto fail;
|
| + goto fail;
|
|
|
| is_proc_lang_bind_spec = (src->flavor == FL_PROCEDURE ? 1 : 0);
|
| if (src->is_bind_c
|
| @@ -1744,10 +1803,10 @@ gfc_add_component (gfc_symbol *sym, const char *name,
|
| }
|
|
|
| if (sym->attr.extension
|
| - && gfc_find_component (sym->components->ts.derived, name, true, true))
|
| + && gfc_find_component (sym->components->ts.u.derived, name, true, true))
|
| {
|
| gfc_error ("Component '%s' at %C already in the parent type "
|
| - "at %L", name, &sym->components->ts.derived->declared_at);
|
| + "at %L", name, &sym->components->ts.u.derived->declared_at);
|
| return FAILURE;
|
| }
|
|
|
| @@ -1761,6 +1820,7 @@ gfc_add_component (gfc_symbol *sym, const char *name,
|
|
|
| p->name = gfc_get_string (name);
|
| p->loc = gfc_current_locus;
|
| + p->ts.type = BT_UNKNOWN;
|
|
|
| *component = p;
|
| return SUCCESS;
|
| @@ -1779,8 +1839,8 @@ switch_types (gfc_symtree *st, gfc_symbol *from, gfc_symbol *to)
|
| return;
|
|
|
| sym = st->n.sym;
|
| - if (sym->ts.type == BT_DERIVED && sym->ts.derived == from)
|
| - sym->ts.derived = to;
|
| + if (sym->ts.type == BT_DERIVED && sym->ts.u.derived == from)
|
| + sym->ts.u.derived = to;
|
|
|
| switch_types (st->left, from, to);
|
| switch_types (st->right, from, to);
|
| @@ -1832,8 +1892,8 @@ gfc_use_derived (gfc_symbol *sym)
|
| for (i = 0; i < GFC_LETTERS; i++)
|
| {
|
| t = &sym->ns->default_type[i];
|
| - if (t->derived == sym)
|
| - t->derived = s;
|
| + if (t->u.derived == sym)
|
| + t->u.derived = s;
|
| }
|
|
|
| st = gfc_find_symtree (sym->ns->sym_root, sym->name);
|
| @@ -1886,7 +1946,7 @@ gfc_find_component (gfc_symbol *sym, const char *name,
|
| && sym->attr.extension
|
| && sym->components->ts.type == BT_DERIVED)
|
| {
|
| - p = gfc_find_component (sym->components->ts.derived, name,
|
| + p = gfc_find_component (sym->components->ts.u.derived, name,
|
| noaccess, silent);
|
| /* Do not overwrite the error. */
|
| if (p == NULL)
|
| @@ -1899,23 +1959,17 @@ gfc_find_component (gfc_symbol *sym, const char *name,
|
|
|
| else if (sym->attr.use_assoc && !noaccess)
|
| {
|
| - if (p->attr.access == ACCESS_PRIVATE)
|
| + bool is_parent_comp = sym->attr.extension && (p == sym->components);
|
| + if (p->attr.access == ACCESS_PRIVATE ||
|
| + (p->attr.access != ACCESS_PUBLIC
|
| + && sym->component_access == ACCESS_PRIVATE
|
| + && !is_parent_comp))
|
| {
|
| if (!silent)
|
| gfc_error ("Component '%s' at %C is a PRIVATE component of '%s'",
|
| name, sym->name);
|
| return NULL;
|
| }
|
| -
|
| - /* If there were components given and all components are private, error
|
| - out at this place. */
|
| - if (p->attr.access != ACCESS_PUBLIC && sym->component_access == ACCESS_PRIVATE)
|
| - {
|
| - if (!silent)
|
| - gfc_error ("All components of '%s' are PRIVATE in structure"
|
| - " constructor at %C", sym->name);
|
| - return NULL;
|
| - }
|
| }
|
|
|
| return p;
|
| @@ -2002,9 +2056,16 @@ gfc_st_label *
|
| gfc_get_st_label (int labelno)
|
| {
|
| gfc_st_label *lp;
|
| + gfc_namespace *ns;
|
| +
|
| + /* Find the namespace of the scoping unit:
|
| + If we're in a BLOCK construct, jump to the parent namespace. */
|
| + ns = gfc_current_ns;
|
| + while (ns->proc_name && ns->proc_name->attr.flavor == FL_LABEL)
|
| + ns = ns->parent;
|
|
|
| /* First see if the label is already in this namespace. */
|
| - lp = gfc_current_ns->st_labels;
|
| + lp = ns->st_labels;
|
| while (lp)
|
| {
|
| if (lp->value == labelno)
|
| @@ -2022,7 +2083,7 @@ gfc_get_st_label (int labelno)
|
| lp->defined = ST_LABEL_UNKNOWN;
|
| lp->referenced = ST_LABEL_UNKNOWN;
|
|
|
| - gfc_insert_bbt (&gfc_current_ns->st_labels, lp, compare_st_labels);
|
| + gfc_insert_bbt (&ns->st_labels, lp, compare_st_labels);
|
|
|
| return lp;
|
| }
|
| @@ -2179,18 +2240,22 @@ gfc_get_namespace (gfc_namespace *parent, int parent_types)
|
| {
|
| gfc_namespace *ns;
|
| gfc_typespec *ts;
|
| - gfc_intrinsic_op in;
|
| + int in;
|
| int i;
|
|
|
| ns = XCNEW (gfc_namespace);
|
| ns->sym_root = NULL;
|
| ns->uop_root = NULL;
|
| + ns->tb_sym_root = NULL;
|
| ns->finalizers = NULL;
|
| ns->default_access = ACCESS_UNKNOWN;
|
| ns->parent = parent;
|
|
|
| for (in = GFC_INTRINSIC_BEGIN; in != GFC_INTRINSIC_END; in++)
|
| - ns->operator_access[in] = ACCESS_UNKNOWN;
|
| + {
|
| + ns->operator_access[in] = ACCESS_UNKNOWN;
|
| + ns->tb_op[in] = NULL;
|
| + }
|
|
|
| /* Initialize default implicit types. */
|
| for (i = 'a'; i <= 'z'; i++)
|
| @@ -2252,7 +2317,6 @@ gfc_new_symtree (gfc_symtree **root, const char *name)
|
|
|
| st = XCNEW (gfc_symtree);
|
| st->name = gfc_get_string (name);
|
| - st->typebound = NULL;
|
|
|
| gfc_insert_bbt (root, st, compare_symtree);
|
| return st;
|
| @@ -2430,6 +2494,19 @@ ambiguous_symbol (const char *name, gfc_symtree *st)
|
| }
|
|
|
|
|
| +/* If we're in a SELECT TYPE block, check if the variable 'st' matches any
|
| + selector on the stack. If yes, replace it by the corresponding temporary. */
|
| +
|
| +static void
|
| +select_type_insert_tmp (gfc_symtree **st)
|
| +{
|
| + gfc_select_type_stack *stack = select_type_stack;
|
| + for (; stack; stack = stack->prev)
|
| + if ((*st)->n.sym == stack->selector && stack->tmp)
|
| + *st = stack->tmp;
|
| +}
|
| +
|
| +
|
| /* Search for a symtree starting in the current namespace, resorting to
|
| any parent namespaces if requested by a nonzero parent_flag.
|
| Returns nonzero if the name is ambiguous. */
|
| @@ -2448,6 +2525,8 @@ gfc_find_sym_tree (const char *name, gfc_namespace *ns, int parent_flag,
|
| st = gfc_find_symtree (ns->sym_root, name);
|
| if (st != NULL)
|
| {
|
| + select_type_insert_tmp (&st);
|
| +
|
| *result = st;
|
| /* Ambiguous generic interfaces are permitted, as long
|
| as the specific interfaces are different. */
|
| @@ -2521,7 +2600,8 @@ save_symbol_data (gfc_symbol *sym)
|
| So if the return value is nonzero, then an error was issued. */
|
|
|
| int
|
| -gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result)
|
| +gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result,
|
| + bool allow_subroutine)
|
| {
|
| gfc_symtree *st;
|
| gfc_symbol *p;
|
| @@ -2562,11 +2642,10 @@ gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result)
|
| }
|
|
|
| p = st->n.sym;
|
| -
|
| if (p->ns != ns && (!p->attr.function || ns->proc_name != p)
|
| - && !(ns->proc_name
|
| - && ns->proc_name->attr.if_source == IFSRC_IFBODY
|
| - && (ns->has_import_set || p->attr.imported)))
|
| + && !(allow_subroutine && p->attr.subroutine)
|
| + && !(ns->proc_name && ns->proc_name->attr.if_source == IFSRC_IFBODY
|
| + && (ns->has_import_set || p->attr.imported)))
|
| {
|
| /* Symbol is from another namespace. */
|
| gfc_error ("Symbol '%s' at %C has already been host associated",
|
| @@ -2591,7 +2670,7 @@ gfc_get_symbol (const char *name, gfc_namespace *ns, gfc_symbol **result)
|
| gfc_symtree *st;
|
| int i;
|
|
|
| - i = gfc_get_sym_tree (name, ns, &st);
|
| + i = gfc_get_sym_tree (name, ns, &st, false);
|
| if (i != 0)
|
| return i;
|
|
|
| @@ -2613,6 +2692,7 @@ gfc_get_ha_sym_tree (const char *name, gfc_symtree **result)
|
| int i;
|
|
|
| i = gfc_find_sym_tree (name, gfc_current_ns, 0, &st);
|
| +
|
| if (st != NULL)
|
| {
|
| save_symbol_data (st->n.sym);
|
| @@ -2633,7 +2713,7 @@ gfc_get_ha_sym_tree (const char *name, gfc_symtree **result)
|
| }
|
| }
|
|
|
| - return gfc_get_sym_tree (name, gfc_current_ns, result);
|
| + return gfc_get_sym_tree (name, gfc_current_ns, result, false);
|
| }
|
|
|
|
|
| @@ -2685,6 +2765,7 @@ void
|
| gfc_undo_symbols (void)
|
| {
|
| gfc_symbol *p, *q, *old;
|
| + tentative_tbp *tbp, *tbq;
|
|
|
| for (p = changed_syms; p; p = q)
|
| {
|
| @@ -2783,6 +2864,14 @@ gfc_undo_symbols (void)
|
| }
|
|
|
| changed_syms = NULL;
|
| +
|
| + for (tbp = tentative_tbp_list; tbp; tbp = tbq)
|
| + {
|
| + tbq = tbp->next;
|
| + /* Procedure is already marked `error' by default. */
|
| + gfc_free (tbp);
|
| + }
|
| + tentative_tbp_list = NULL;
|
| }
|
|
|
|
|
| @@ -2820,6 +2909,7 @@ void
|
| gfc_commit_symbols (void)
|
| {
|
| gfc_symbol *p, *q;
|
| + tentative_tbp *tbp, *tbq;
|
|
|
| for (p = changed_syms; p; p = q)
|
| {
|
| @@ -2830,6 +2920,14 @@ gfc_commit_symbols (void)
|
| free_old_symbol (p);
|
| }
|
| changed_syms = NULL;
|
| +
|
| + for (tbp = tentative_tbp_list; tbp; tbp = tbq)
|
| + {
|
| + tbq = tbp->next;
|
| + tbp->proc->error = 0;
|
| + gfc_free (tbp);
|
| + }
|
| + tentative_tbp_list = NULL;
|
| }
|
|
|
|
|
| @@ -2861,6 +2959,24 @@ gfc_commit_symbol (gfc_symbol *sym)
|
| }
|
|
|
|
|
| +/* Recursively free trees containing type-bound procedures. */
|
| +
|
| +static void
|
| +free_tb_tree (gfc_symtree *t)
|
| +{
|
| + if (t == NULL)
|
| + return;
|
| +
|
| + free_tb_tree (t->left);
|
| + free_tb_tree (t->right);
|
| +
|
| + /* TODO: Free type-bound procedure structs themselves; probably needs some
|
| + sort of ref-counting mechanism. */
|
| +
|
| + gfc_free (t);
|
| +}
|
| +
|
| +
|
| /* Recursive function that deletes an entire tree and all the common
|
| head structures it points to. */
|
|
|
| @@ -2883,7 +2999,6 @@ free_common_tree (gfc_symtree * common_tree)
|
| static void
|
| free_uop_tree (gfc_symtree *uop_tree)
|
| {
|
| -
|
| if (uop_tree == NULL)
|
| return;
|
|
|
| @@ -2891,7 +3006,6 @@ free_uop_tree (gfc_symtree *uop_tree)
|
| free_uop_tree (uop_tree->right);
|
|
|
| gfc_free_interface (uop_tree->n.uop->op);
|
| -
|
| gfc_free (uop_tree->n.uop);
|
| gfc_free (uop_tree);
|
| }
|
| @@ -2938,7 +3052,7 @@ free_sym_tree (gfc_symtree *sym_tree)
|
|
|
| /* Free the derived type list. */
|
|
|
| -static void
|
| +void
|
| gfc_free_dt_list (void)
|
| {
|
| gfc_dt_list *dt, *n;
|
| @@ -3008,6 +3122,33 @@ gfc_free_finalizer_list (gfc_finalizer* list)
|
| }
|
|
|
|
|
| +/* Create a new gfc_charlen structure and add it to a namespace.
|
| + If 'old_cl' is given, the newly created charlen will be a copy of it. */
|
| +
|
| +gfc_charlen*
|
| +gfc_new_charlen (gfc_namespace *ns, gfc_charlen *old_cl)
|
| +{
|
| + gfc_charlen *cl;
|
| + cl = gfc_get_charlen ();
|
| +
|
| + /* Put into namespace. */
|
| + cl->next = ns->cl_list;
|
| + ns->cl_list = cl;
|
| +
|
| + /* Copy old_cl. */
|
| + if (old_cl)
|
| + {
|
| + cl->length = gfc_copy_expr (old_cl->length);
|
| + cl->length_from_typespec = old_cl->length_from_typespec;
|
| + cl->backend_decl = old_cl->backend_decl;
|
| + cl->passed_length = old_cl->passed_length;
|
| + cl->resolved = old_cl->resolved;
|
| + }
|
| +
|
| + return cl;
|
| +}
|
| +
|
| +
|
| /* Free the charlen list from cl to end (end is not freed).
|
| Free the whole list if end is NULL. */
|
|
|
| @@ -3034,7 +3175,7 @@ void
|
| gfc_free_namespace (gfc_namespace *ns)
|
| {
|
| gfc_namespace *p, *q;
|
| - gfc_intrinsic_op i;
|
| + int i;
|
|
|
| if (ns == NULL)
|
| return;
|
| @@ -3049,6 +3190,8 @@ gfc_free_namespace (gfc_namespace *ns)
|
| free_sym_tree (ns->sym_root);
|
| free_uop_tree (ns->uop_root);
|
| free_common_tree (ns->common_root);
|
| + free_tb_tree (ns->tb_sym_root);
|
| + free_tb_tree (ns->tb_uop_root);
|
| gfc_free_finalizer_list (ns->finalizers);
|
| gfc_free_charlen (ns->cl_list, NULL);
|
| free_st_labels (ns->st_labels);
|
| @@ -3180,8 +3323,8 @@ gfc_is_var_automatic (gfc_symbol *sym)
|
| return true;
|
| /* Check for non-constant length character variables. */
|
| if (sym->ts.type == BT_CHARACTER
|
| - && sym->ts.cl
|
| - && !gfc_is_constant_expr (sym->ts.cl->length))
|
| + && sym->ts.u.cl
|
| + && !gfc_is_constant_expr (sym->ts.u.cl->length))
|
| return true;
|
| return false;
|
| }
|
| @@ -3375,6 +3518,15 @@ verify_bind_c_derived_type (gfc_symbol *derived_sym)
|
| retval = FAILURE;
|
| }
|
|
|
| + if (curr_comp->attr.proc_pointer != 0)
|
| + {
|
| + gfc_error ("Procedure pointer component '%s' at %L cannot be a member"
|
| + " of the BIND(C) derived type '%s' at %L", curr_comp->name,
|
| + &curr_comp->loc, derived_sym->name,
|
| + &derived_sym->declared_at);
|
| + retval = FAILURE;
|
| + }
|
| +
|
| /* The components cannot be allocatable.
|
| J3/04-007, Section 15.2.3, C1505. */
|
| if (curr_comp->attr.allocatable != 0)
|
| @@ -3389,14 +3541,14 @@ verify_bind_c_derived_type (gfc_symbol *derived_sym)
|
|
|
| /* BIND(C) derived types must have interoperable components. */
|
| if (curr_comp->ts.type == BT_DERIVED
|
| - && curr_comp->ts.derived->ts.is_iso_c != 1
|
| - && curr_comp->ts.derived != derived_sym)
|
| + && curr_comp->ts.u.derived->ts.is_iso_c != 1
|
| + && curr_comp->ts.u.derived != derived_sym)
|
| {
|
| /* This should be allowed; the draft says a derived-type can not
|
| have type parameters if it is has the BIND attribute. Type
|
| parameters seem to be for making parameterized derived types.
|
| There's no need to verify the type if it is c_ptr/c_funptr. */
|
| - retval = verify_bind_c_derived_type (curr_comp->ts.derived);
|
| + retval = verify_bind_c_derived_type (curr_comp->ts.u.derived);
|
| }
|
| else
|
| {
|
| @@ -3495,10 +3647,10 @@ gen_special_c_interop_ptr (int ptr_id, const char *ptr_name,
|
| /* The c_ptr and c_funptr derived types will provide the
|
| definition for c_null_ptr and c_null_funptr, respectively. */
|
| if (ptr_id == ISOCBINDING_NULL_PTR)
|
| - tmp_sym->ts.derived = get_iso_c_binding_dt (ISOCBINDING_PTR);
|
| + tmp_sym->ts.u.derived = get_iso_c_binding_dt (ISOCBINDING_PTR);
|
| else
|
| - tmp_sym->ts.derived = get_iso_c_binding_dt (ISOCBINDING_FUNPTR);
|
| - if (tmp_sym->ts.derived == NULL)
|
| + tmp_sym->ts.u.derived = get_iso_c_binding_dt (ISOCBINDING_FUNPTR);
|
| + if (tmp_sym->ts.u.derived == NULL)
|
| {
|
| /* This can occur if the user forgot to declare c_ptr or
|
| c_funptr and they're trying to use one of the procedures
|
| @@ -3511,7 +3663,7 @@ gen_special_c_interop_ptr (int ptr_id, const char *ptr_name,
|
| ? "_gfortran_iso_c_binding_c_ptr"
|
| : "_gfortran_iso_c_binding_c_funptr"));
|
|
|
| - tmp_sym->ts.derived =
|
| + tmp_sym->ts.u.derived =
|
| get_iso_c_binding_dt (ptr_id == ISOCBINDING_NULL_PTR
|
| ? ISOCBINDING_PTR : ISOCBINDING_FUNPTR);
|
| }
|
| @@ -3532,11 +3684,11 @@ gen_special_c_interop_ptr (int ptr_id, const char *ptr_name,
|
| tmp_sym->value = gfc_get_expr ();
|
| tmp_sym->value->expr_type = EXPR_STRUCTURE;
|
| tmp_sym->value->ts.type = BT_DERIVED;
|
| - tmp_sym->value->ts.derived = tmp_sym->ts.derived;
|
| - /* Create a constructor with no expr, that way we can recognize if the user
|
| - tries to call the structure constructor for one of the iso_c_binding
|
| - derived types during resolution (resolve_structure_cons). */
|
| + tmp_sym->value->ts.u.derived = tmp_sym->ts.u.derived;
|
| tmp_sym->value->value.constructor = gfc_get_constructor ();
|
| + tmp_sym->value->value.constructor->expr = gfc_get_expr ();
|
| + tmp_sym->value->value.constructor->expr->expr_type = EXPR_NULL;
|
| + tmp_sym->value->value.constructor->expr->ts.is_iso_c = 1;
|
| /* Must declare c_null_ptr and c_null_funptr as having the
|
| PARAMETER attribute so they can be used in init expressions. */
|
| tmp_sym->attr.flavor = FL_PARAMETER;
|
| @@ -3598,7 +3750,7 @@ gen_cptr_param (gfc_formal_arglist **head,
|
| c_ptr_in = "gfc_cptr__";
|
| else
|
| c_ptr_in = c_ptr_name;
|
| - gfc_get_sym_tree (c_ptr_in, ns, ¶m_symtree);
|
| + gfc_get_sym_tree (c_ptr_in, ns, ¶m_symtree, false);
|
| if (param_symtree != NULL)
|
| param_sym = param_symtree->n.sym;
|
| else
|
| @@ -3636,7 +3788,7 @@ gen_cptr_param (gfc_formal_arglist **head,
|
| gfc_get_ha_symbol (c_ptr_type, &(c_ptr_sym));
|
| }
|
|
|
| - param_sym->ts.derived = c_ptr_sym;
|
| + param_sym->ts.u.derived = c_ptr_sym;
|
| param_sym->module = gfc_get_string (module_name);
|
|
|
| /* Make new formal arg. */
|
| @@ -3664,7 +3816,7 @@ gen_fptr_param (gfc_formal_arglist **head,
|
| if (f_ptr_name != NULL)
|
| f_ptr_out = f_ptr_name;
|
|
|
| - gfc_get_sym_tree (f_ptr_out, ns, ¶m_symtree);
|
| + gfc_get_sym_tree (f_ptr_out, ns, ¶m_symtree, false);
|
| if (param_symtree != NULL)
|
| param_sym = param_symtree->n.sym;
|
| else
|
| @@ -3711,7 +3863,7 @@ gen_shape_param (gfc_formal_arglist **head,
|
| if (shape_param_name != NULL)
|
| shape_param = shape_param_name;
|
|
|
| - gfc_get_sym_tree (shape_param, ns, ¶m_symtree);
|
| + gfc_get_sym_tree (shape_param, ns, ¶m_symtree, false);
|
| if (param_symtree != NULL)
|
| param_sym = param_symtree->n.sym;
|
| else
|
| @@ -3761,6 +3913,7 @@ gen_shape_param (gfc_formal_arglist **head,
|
| add_formal_arg (head, tail, formal_arg, param_sym);
|
| }
|
|
|
| +
|
| /* Add a procedure interface to the given symbol (i.e., store a
|
| reference to the list of formal arguments). */
|
|
|
| @@ -3773,6 +3926,7 @@ add_proc_interface (gfc_symbol *sym, ifsrc source,
|
| sym->attr.if_source = source;
|
| }
|
|
|
| +
|
| /* Copy the formal args from an existing symbol, src, into a new
|
| symbol, dest. New formal args are created, and the description of
|
| each arg is set according to the existing ones. This function is
|
| @@ -3781,7 +3935,7 @@ add_proc_interface (gfc_symbol *sym, ifsrc source,
|
| args based on the args of a given named interface. */
|
|
|
| void
|
| -copy_formal_args (gfc_symbol *dest, gfc_symbol *src)
|
| +gfc_copy_formal_args (gfc_symbol *dest, gfc_symbol *src)
|
| {
|
| gfc_formal_arglist *head = NULL;
|
| gfc_formal_arglist *tail = NULL;
|
| @@ -3805,7 +3959,7 @@ copy_formal_args (gfc_symbol *dest, gfc_symbol *src)
|
| formal_arg->sym->attr = curr_arg->sym->attr;
|
| formal_arg->sym->ts = curr_arg->sym->ts;
|
| formal_arg->sym->as = gfc_copy_array_spec (curr_arg->sym->as);
|
| - copy_formal_args (formal_arg->sym, curr_arg->sym);
|
| + gfc_copy_formal_args (formal_arg->sym, curr_arg->sym);
|
|
|
| /* If this isn't the first arg, set up the next ptr. For the
|
| last arg built, the formal_arg->next will never get set to
|
| @@ -3832,6 +3986,118 @@ copy_formal_args (gfc_symbol *dest, gfc_symbol *src)
|
| gfc_current_ns = parent_ns;
|
| }
|
|
|
| +
|
| +void
|
| +gfc_copy_formal_args_intr (gfc_symbol *dest, gfc_intrinsic_sym *src)
|
| +{
|
| + gfc_formal_arglist *head = NULL;
|
| + gfc_formal_arglist *tail = NULL;
|
| + gfc_formal_arglist *formal_arg = NULL;
|
| + gfc_intrinsic_arg *curr_arg = NULL;
|
| + gfc_formal_arglist *formal_prev = NULL;
|
| + /* Save current namespace so we can change it for formal args. */
|
| + gfc_namespace *parent_ns = gfc_current_ns;
|
| +
|
| + /* Create a new namespace, which will be the formal ns (namespace
|
| + of the formal args). */
|
| + gfc_current_ns = gfc_get_namespace (parent_ns, 0);
|
| + gfc_current_ns->proc_name = dest;
|
| +
|
| + for (curr_arg = src->formal; curr_arg; curr_arg = curr_arg->next)
|
| + {
|
| + formal_arg = gfc_get_formal_arglist ();
|
| + gfc_get_symbol (curr_arg->name, gfc_current_ns, &(formal_arg->sym));
|
| +
|
| + /* May need to copy more info for the symbol. */
|
| + formal_arg->sym->ts = curr_arg->ts;
|
| + formal_arg->sym->attr.optional = curr_arg->optional;
|
| + formal_arg->sym->attr.intent = curr_arg->intent;
|
| + formal_arg->sym->attr.flavor = FL_VARIABLE;
|
| + formal_arg->sym->attr.dummy = 1;
|
| +
|
| + if (formal_arg->sym->ts.type == BT_CHARACTER)
|
| + formal_arg->sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
|
| +
|
| + /* If this isn't the first arg, set up the next ptr. For the
|
| + last arg built, the formal_arg->next will never get set to
|
| + anything other than NULL. */
|
| + if (formal_prev != NULL)
|
| + formal_prev->next = formal_arg;
|
| + else
|
| + formal_arg->next = NULL;
|
| +
|
| + formal_prev = formal_arg;
|
| +
|
| + /* Add arg to list of formal args. */
|
| + add_formal_arg (&head, &tail, formal_arg, formal_arg->sym);
|
| + }
|
| +
|
| + /* Add the interface to the symbol. */
|
| + add_proc_interface (dest, IFSRC_DECL, head);
|
| +
|
| + /* Store the formal namespace information. */
|
| + if (dest->formal != NULL)
|
| + /* The current ns should be that for the dest proc. */
|
| + dest->formal_ns = gfc_current_ns;
|
| + /* Restore the current namespace to what it was on entry. */
|
| + gfc_current_ns = parent_ns;
|
| +}
|
| +
|
| +
|
| +void
|
| +gfc_copy_formal_args_ppc (gfc_component *dest, gfc_symbol *src)
|
| +{
|
| + gfc_formal_arglist *head = NULL;
|
| + gfc_formal_arglist *tail = NULL;
|
| + gfc_formal_arglist *formal_arg = NULL;
|
| + gfc_formal_arglist *curr_arg = NULL;
|
| + gfc_formal_arglist *formal_prev = NULL;
|
| + /* Save current namespace so we can change it for formal args. */
|
| + gfc_namespace *parent_ns = gfc_current_ns;
|
| +
|
| + /* Create a new namespace, which will be the formal ns (namespace
|
| + of the formal args). */
|
| + gfc_current_ns = gfc_get_namespace (parent_ns, 0);
|
| + /* TODO: gfc_current_ns->proc_name = dest;*/
|
| +
|
| + for (curr_arg = src->formal; curr_arg; curr_arg = curr_arg->next)
|
| + {
|
| + formal_arg = gfc_get_formal_arglist ();
|
| + gfc_get_symbol (curr_arg->sym->name, gfc_current_ns, &(formal_arg->sym));
|
| +
|
| + /* May need to copy more info for the symbol. */
|
| + formal_arg->sym->attr = curr_arg->sym->attr;
|
| + formal_arg->sym->ts = curr_arg->sym->ts;
|
| + formal_arg->sym->as = gfc_copy_array_spec (curr_arg->sym->as);
|
| + gfc_copy_formal_args (formal_arg->sym, curr_arg->sym);
|
| +
|
| + /* If this isn't the first arg, set up the next ptr. For the
|
| + last arg built, the formal_arg->next will never get set to
|
| + anything other than NULL. */
|
| + if (formal_prev != NULL)
|
| + formal_prev->next = formal_arg;
|
| + else
|
| + formal_arg->next = NULL;
|
| +
|
| + formal_prev = formal_arg;
|
| +
|
| + /* Add arg to list of formal args. */
|
| + add_formal_arg (&head, &tail, formal_arg, formal_arg->sym);
|
| + }
|
| +
|
| + /* Add the interface to the symbol. */
|
| + dest->formal = head;
|
| + dest->attr.if_source = IFSRC_DECL;
|
| +
|
| + /* Store the formal namespace information. */
|
| + if (dest->formal != NULL)
|
| + /* The current ns should be that for the dest proc. */
|
| + dest->formal_ns = gfc_current_ns;
|
| + /* Restore the current namespace to what it was on entry. */
|
| + gfc_current_ns = parent_ns;
|
| +}
|
| +
|
| +
|
| /* Builds the parameter list for the iso_c_binding procedure
|
| c_f_pointer or c_f_procpointer. The old_sym typically refers to a
|
| generic version of either the c_f_pointer or c_f_procpointer
|
| @@ -3949,7 +4215,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
|
| return;
|
|
|
| /* Create the sym tree in the current ns. */
|
| - gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree);
|
| + gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
|
| if (tmp_symtree)
|
| tmp_sym = tmp_symtree->n.sym;
|
| else
|
| @@ -4013,8 +4279,8 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
|
| tmp_sym->value->value.character.string[0]
|
| = (gfc_char_t) c_interop_kinds_table[s].value;
|
| tmp_sym->value->value.character.string[1] = '\0';
|
| - tmp_sym->ts.cl = gfc_get_charlen ();
|
| - tmp_sym->ts.cl->length = gfc_int_expr (1);
|
| + tmp_sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
|
| + tmp_sym->ts.u.cl->length = gfc_int_expr (1);
|
|
|
| /* May not need this in both attr and ts, but do need in
|
| attr for writing module file. */
|
| @@ -4058,7 +4324,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
|
|
|
| tmp_sym->attr.referenced = 1;
|
|
|
| - tmp_sym->ts.derived = tmp_sym;
|
| + tmp_sym->ts.u.derived = tmp_sym;
|
|
|
| /* Add the symbol created for the derived type to the current ns. */
|
| dt_list_ptr = &(gfc_derived_types);
|
| @@ -4143,13 +4409,13 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
|
| C address of. */
|
| tmp_sym->ts.type = BT_DERIVED;
|
| if (s == ISOCBINDING_LOC)
|
| - tmp_sym->ts.derived =
|
| + tmp_sym->ts.u.derived =
|
| get_iso_c_binding_dt (ISOCBINDING_PTR);
|
| else
|
| - tmp_sym->ts.derived =
|
| + tmp_sym->ts.u.derived =
|
| get_iso_c_binding_dt (ISOCBINDING_FUNPTR);
|
|
|
| - if (tmp_sym->ts.derived == NULL)
|
| + if (tmp_sym->ts.u.derived == NULL)
|
| {
|
| /* Create the necessary derived type so we can continue
|
| processing the file. */
|
| @@ -4159,7 +4425,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
|
| (const char *)(s == ISOCBINDING_FUNLOC
|
| ? "_gfortran_iso_c_binding_c_funptr"
|
| : "_gfortran_iso_c_binding_c_ptr"));
|
| - tmp_sym->ts.derived =
|
| + tmp_sym->ts.u.derived =
|
| get_iso_c_binding_dt (s == ISOCBINDING_FUNLOC
|
| ? ISOCBINDING_FUNPTR
|
| : ISOCBINDING_PTR);
|
| @@ -4237,6 +4503,8 @@ get_iso_c_sym (gfc_symbol *old_sym, char *new_name,
|
| new_symtree->n.sym->module = gfc_get_string (old_sym->module);
|
| new_symtree->n.sym->from_intmod = old_sym->from_intmod;
|
| new_symtree->n.sym->intmod_sym_id = old_sym->intmod_sym_id;
|
| + if (old_sym->attr.function)
|
| + new_symtree->n.sym->result = new_symtree->n.sym;
|
| /* Build the formal arg list. */
|
| build_formal_args (new_symtree->n.sym, old_sym, add_optional_arg);
|
|
|
| @@ -4280,6 +4548,27 @@ gfc_check_symbol_typed (gfc_symbol* sym, gfc_namespace* ns,
|
| }
|
|
|
|
|
| +/* Construct a typebound-procedure structure. Those are stored in a tentative
|
| + list and marked `error' until symbols are committed. */
|
| +
|
| +gfc_typebound_proc*
|
| +gfc_get_typebound_proc (void)
|
| +{
|
| + gfc_typebound_proc *result;
|
| + tentative_tbp *list_node;
|
| +
|
| + result = XCNEW (gfc_typebound_proc);
|
| + result->error = 1;
|
| +
|
| + list_node = XCNEW (tentative_tbp);
|
| + list_node->next = tentative_tbp_list;
|
| + list_node->proc = result;
|
| + tentative_tbp_list = list_node;
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| /* Get the super-type of a given derived type. */
|
|
|
| gfc_symbol*
|
| @@ -4290,38 +4579,383 @@ gfc_get_derived_super_type (gfc_symbol* derived)
|
|
|
| gcc_assert (derived->components);
|
| gcc_assert (derived->components->ts.type == BT_DERIVED);
|
| - gcc_assert (derived->components->ts.derived);
|
| + gcc_assert (derived->components->ts.u.derived);
|
| +
|
| + return derived->components->ts.u.derived;
|
| +}
|
| +
|
| +
|
| +/* Get the ultimate super-type of a given derived type. */
|
| +
|
| +gfc_symbol*
|
| +gfc_get_ultimate_derived_super_type (gfc_symbol* derived)
|
| +{
|
| + if (!derived->attr.extension)
|
| + return NULL;
|
| +
|
| + derived = gfc_get_derived_super_type (derived);
|
| +
|
| + if (derived->attr.extension)
|
| + return gfc_get_ultimate_derived_super_type (derived);
|
| + else
|
| + return derived;
|
| +}
|
| +
|
|
|
| - return derived->components->ts.derived;
|
| +/* Check if a derived type t2 is an extension of (or equal to) a type t1. */
|
| +
|
| +bool
|
| +gfc_type_is_extension_of (gfc_symbol *t1, gfc_symbol *t2)
|
| +{
|
| + while (!gfc_compare_derived_types (t1, t2) && t2->attr.extension)
|
| + t2 = gfc_get_derived_super_type (t2);
|
| + return gfc_compare_derived_types (t1, t2);
|
| }
|
|
|
|
|
| -/* Find a type-bound procedure by name for a derived-type (looking recursively
|
| - through the super-types). */
|
| +/* Check if two typespecs are type compatible (F03:5.1.1.2):
|
| + If ts1 is nonpolymorphic, ts2 must be the same type.
|
| + If ts1 is polymorphic (CLASS), ts2 must be an extension of ts1. */
|
| +
|
| +bool
|
| +gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2)
|
| +{
|
| + gfc_component *cmp1, *cmp2;
|
| +
|
| + bool is_class1 = (ts1->type == BT_CLASS);
|
| + bool is_class2 = (ts2->type == BT_CLASS);
|
| + bool is_derived1 = (ts1->type == BT_DERIVED);
|
| + bool is_derived2 = (ts2->type == BT_DERIVED);
|
| +
|
| + if (!is_derived1 && !is_derived2 && !is_class1 && !is_class2)
|
| + return (ts1->type == ts2->type);
|
| +
|
| + if (is_derived1 && is_derived2)
|
| + return gfc_compare_derived_types (ts1->u.derived, ts2->u.derived);
|
| +
|
| + cmp1 = cmp2 = NULL;
|
| +
|
| + if (is_class1)
|
| + {
|
| + cmp1 = gfc_find_component (ts1->u.derived, "$data", true, false);
|
| + if (cmp1 == NULL)
|
| + return 0;
|
| + }
|
| +
|
| + if (is_class2)
|
| + {
|
| + cmp2 = gfc_find_component (ts2->u.derived, "$data", true, false);
|
| + if (cmp2 == NULL)
|
| + return 0;
|
| + }
|
| +
|
| + if (is_class1 && is_derived2)
|
| + return gfc_type_is_extension_of (cmp1->ts.u.derived, ts2->u.derived);
|
| +
|
| + else if (is_class1 && is_class2)
|
| + return gfc_type_is_extension_of (cmp1->ts.u.derived, cmp2->ts.u.derived);
|
| +
|
| + else
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +/* Build a polymorphic CLASS entity, using the symbol that comes from
|
| + build_sym. A CLASS entity is represented by an encapsulating type,
|
| + which contains the declared type as '$data' component, plus a pointer
|
| + component '$vptr' which determines the dynamic type. */
|
| +
|
| +gfc_try
|
| +gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
|
| + gfc_array_spec **as)
|
| +{
|
| + char name[GFC_MAX_SYMBOL_LEN + 5];
|
| + gfc_symbol *fclass;
|
| + gfc_symbol *vtab;
|
| + gfc_component *c;
|
| +
|
| + /* Determine the name of the encapsulating type. */
|
| + if ((*as) && (*as)->rank && attr->allocatable)
|
| + sprintf (name, ".class.%s.%d.a", ts->u.derived->name, (*as)->rank);
|
| + else if ((*as) && (*as)->rank)
|
| + sprintf (name, ".class.%s.%d", ts->u.derived->name, (*as)->rank);
|
| + else if (attr->allocatable)
|
| + sprintf (name, ".class.%s.a", ts->u.derived->name);
|
| + else
|
| + sprintf (name, ".class.%s", ts->u.derived->name);
|
| +
|
| + gfc_find_symbol (name, ts->u.derived->ns, 0, &fclass);
|
| + if (fclass == NULL)
|
| + {
|
| + gfc_symtree *st;
|
| + /* If not there, create a new symbol. */
|
| + fclass = gfc_new_symbol (name, ts->u.derived->ns);
|
| + st = gfc_new_symtree (&ts->u.derived->ns->sym_root, name);
|
| + st->n.sym = fclass;
|
| + gfc_set_sym_referenced (fclass);
|
| + fclass->refs++;
|
| + fclass->ts.type = BT_UNKNOWN;
|
| + fclass->attr.abstract = ts->u.derived->attr.abstract;
|
| + if (ts->u.derived->f2k_derived)
|
| + fclass->f2k_derived = gfc_get_namespace (NULL, 0);
|
| + if (gfc_add_flavor (&fclass->attr, FL_DERIVED,
|
| + NULL, &gfc_current_locus) == FAILURE)
|
| + return FAILURE;
|
| +
|
| + /* Add component '$data'. */
|
| + if (gfc_add_component (fclass, "$data", &c) == FAILURE)
|
| + return FAILURE;
|
| + c->ts = *ts;
|
| + c->ts.type = BT_DERIVED;
|
| + c->attr.access = ACCESS_PRIVATE;
|
| + c->ts.u.derived = ts->u.derived;
|
| + c->attr.class_pointer = attr->pointer;
|
| + c->attr.pointer = attr->pointer || attr->dummy;
|
| + c->attr.allocatable = attr->allocatable;
|
| + c->attr.dimension = attr->dimension;
|
| + c->attr.abstract = ts->u.derived->attr.abstract;
|
| + c->as = (*as);
|
| + c->initializer = gfc_get_expr ();
|
| + c->initializer->expr_type = EXPR_NULL;
|
| +
|
| + /* Add component '$vptr'. */
|
| + if (gfc_add_component (fclass, "$vptr", &c) == FAILURE)
|
| + return FAILURE;
|
| + c->ts.type = BT_DERIVED;
|
| + vtab = gfc_find_derived_vtab (ts->u.derived);
|
| + gcc_assert (vtab);
|
| + c->ts.u.derived = vtab->ts.u.derived;
|
| + c->attr.pointer = 1;
|
| + c->initializer = gfc_get_expr ();
|
| + c->initializer->expr_type = EXPR_NULL;
|
| + }
|
| +
|
| + /* Since the extension field is 8 bit wide, we can only have
|
| + up to 255 extension levels. */
|
| + if (ts->u.derived->attr.extension == 255)
|
| + {
|
| + gfc_error ("Maximum extension level reached with type '%s' at %L",
|
| + ts->u.derived->name, &ts->u.derived->declared_at);
|
| + return FAILURE;
|
| + }
|
| +
|
| + fclass->attr.extension = ts->u.derived->attr.extension + 1;
|
| + fclass->attr.is_class = 1;
|
| + ts->u.derived = fclass;
|
| + attr->allocatable = attr->pointer = attr->dimension = 0;
|
| + (*as) = NULL; /* XXX */
|
| + return SUCCESS;
|
| +}
|
| +
|
| +
|
| +/* Find the symbol for a derived type's vtab. */
|
| +
|
| +gfc_symbol *
|
| +gfc_find_derived_vtab (gfc_symbol *derived)
|
| +{
|
| + gfc_namespace *ns;
|
| + gfc_symbol *vtab = NULL, *vtype = NULL;
|
| + char name[2 * GFC_MAX_SYMBOL_LEN + 8];
|
| +
|
| + ns = gfc_current_ns;
|
| +
|
| + for (; ns; ns = ns->parent)
|
| + if (!ns->parent)
|
| + break;
|
| +
|
| + if (ns)
|
| + {
|
| + sprintf (name, "vtab$%s", derived->name);
|
| + gfc_find_symbol (name, ns, 0, &vtab);
|
| +
|
| + if (vtab == NULL)
|
| + {
|
| + gfc_get_symbol (name, ns, &vtab);
|
| + vtab->ts.type = BT_DERIVED;
|
| + vtab->attr.flavor = FL_VARIABLE;
|
| + vtab->attr.target = 1;
|
| + vtab->attr.save = SAVE_EXPLICIT;
|
| + vtab->attr.vtab = 1;
|
| + vtab->attr.access = ACCESS_PRIVATE;
|
| + vtab->refs++;
|
| + gfc_set_sym_referenced (vtab);
|
| + sprintf (name, "vtype$%s", derived->name);
|
| +
|
| + gfc_find_symbol (name, ns, 0, &vtype);
|
| + if (vtype == NULL)
|
| + {
|
| + gfc_component *c;
|
| + gfc_symbol *parent = NULL, *parent_vtab = NULL;
|
| +
|
| + gfc_get_symbol (name, ns, &vtype);
|
| + if (gfc_add_flavor (&vtype->attr, FL_DERIVED,
|
| + NULL, &gfc_current_locus) == FAILURE)
|
| + return NULL;
|
| + vtype->refs++;
|
| + gfc_set_sym_referenced (vtype);
|
| + vtype->attr.access = ACCESS_PRIVATE;
|
| +
|
| + /* Add component '$hash'. */
|
| + if (gfc_add_component (vtype, "$hash", &c) == FAILURE)
|
| + return NULL;
|
| + c->ts.type = BT_INTEGER;
|
| + c->ts.kind = 4;
|
| + c->attr.access = ACCESS_PRIVATE;
|
| + c->initializer = gfc_int_expr (derived->hash_value);
|
| +
|
| + /* Add component '$size'. */
|
| + if (gfc_add_component (vtype, "$size", &c) == FAILURE)
|
| + return NULL;
|
| + c->ts.type = BT_INTEGER;
|
| + c->ts.kind = 4;
|
| + c->attr.access = ACCESS_PRIVATE;
|
| + /* Remember the derived type in ts.u.derived,
|
| + so that the correct initializer can be set later on
|
| + (in gfc_conv_structure). */
|
| + c->ts.u.derived = derived;
|
| + c->initializer = gfc_int_expr (0);
|
| +
|
| + /* Add component $extends. */
|
| + if (gfc_add_component (vtype, "$extends", &c) == FAILURE)
|
| + return NULL;
|
| + c->attr.pointer = 1;
|
| + c->attr.access = ACCESS_PRIVATE;
|
| + c->initializer = gfc_get_expr ();
|
| + parent = gfc_get_derived_super_type (derived);
|
| + if (parent)
|
| + {
|
| + parent_vtab = gfc_find_derived_vtab (parent);
|
| + c->ts.type = BT_DERIVED;
|
| + c->ts.u.derived = parent_vtab->ts.u.derived;
|
| + c->initializer->expr_type = EXPR_VARIABLE;
|
| + gfc_find_sym_tree (parent_vtab->name, parent_vtab->ns, 0,
|
| + &c->initializer->symtree);
|
| + }
|
| + else
|
| + {
|
| + c->ts.type = BT_DERIVED;
|
| + c->ts.u.derived = vtype;
|
| + c->initializer->expr_type = EXPR_NULL;
|
| + }
|
| + }
|
| + vtab->ts.u.derived = vtype;
|
| +
|
| + vtab->value = gfc_default_initializer (&vtab->ts);
|
| + }
|
| + }
|
| +
|
| + return vtab;
|
| +}
|
| +
|
| +
|
| +/* General worker function to find either a type-bound procedure or a
|
| + type-bound user operator. */
|
| +
|
| +static gfc_symtree*
|
| +find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
|
| + const char* name, bool noaccess, bool uop,
|
| + locus* where)
|
| +{
|
| + gfc_symtree* res;
|
| + gfc_symtree* root;
|
| +
|
| + /* Set correct symbol-root. */
|
| + gcc_assert (derived->f2k_derived);
|
| + root = (uop ? derived->f2k_derived->tb_uop_root
|
| + : derived->f2k_derived->tb_sym_root);
|
| +
|
| + /* Set default to failure. */
|
| + if (t)
|
| + *t = FAILURE;
|
| +
|
| + /* Try to find it in the current type's namespace. */
|
| + res = gfc_find_symtree (root, name);
|
| + if (res && res->n.tb && !res->n.tb->error)
|
| + {
|
| + /* We found one. */
|
| + if (t)
|
| + *t = SUCCESS;
|
| +
|
| + if (!noaccess && derived->attr.use_assoc
|
| + && res->n.tb->access == ACCESS_PRIVATE)
|
| + {
|
| + if (where)
|
| + gfc_error ("'%s' of '%s' is PRIVATE at %L",
|
| + name, derived->name, where);
|
| + if (t)
|
| + *t = FAILURE;
|
| + }
|
| +
|
| + return res;
|
| + }
|
| +
|
| + /* Otherwise, recurse on parent type if derived is an extension. */
|
| + if (derived->attr.extension)
|
| + {
|
| + gfc_symbol* super_type;
|
| + super_type = gfc_get_derived_super_type (derived);
|
| + gcc_assert (super_type);
|
| +
|
| + return find_typebound_proc_uop (super_type, t, name,
|
| + noaccess, uop, where);
|
| + }
|
| +
|
| + /* Nothing found. */
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +/* Find a type-bound procedure or user operator by name for a derived-type
|
| + (looking recursively through the super-types). */
|
|
|
| gfc_symtree*
|
| gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
|
| - const char* name, bool noaccess)
|
| + const char* name, bool noaccess, locus* where)
|
| {
|
| - gfc_symtree* res;
|
| + return find_typebound_proc_uop (derived, t, name, noaccess, false, where);
|
| +}
|
| +
|
| +gfc_symtree*
|
| +gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
|
| + const char* name, bool noaccess, locus* where)
|
| +{
|
| + return find_typebound_proc_uop (derived, t, name, noaccess, true, where);
|
| +}
|
| +
|
| +
|
| +/* Find a type-bound intrinsic operator looking recursively through the
|
| + super-type hierarchy. */
|
| +
|
| +gfc_typebound_proc*
|
| +gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
|
| + gfc_intrinsic_op op, bool noaccess,
|
| + locus* where)
|
| +{
|
| + gfc_typebound_proc* res;
|
|
|
| /* Set default to failure. */
|
| if (t)
|
| *t = FAILURE;
|
|
|
| /* Try to find it in the current type's namespace. */
|
| - gcc_assert (derived->f2k_derived);
|
| - res = gfc_find_symtree (derived->f2k_derived->sym_root, name);
|
| - if (res && res->typebound)
|
| + if (derived->f2k_derived)
|
| + res = derived->f2k_derived->tb_op[op];
|
| + else
|
| + res = NULL;
|
| +
|
| + /* Check access. */
|
| + if (res && !res->error)
|
| {
|
| /* We found one. */
|
| if (t)
|
| *t = SUCCESS;
|
|
|
| if (!noaccess && derived->attr.use_assoc
|
| - && res->typebound->access == ACCESS_PRIVATE)
|
| + && res->access == ACCESS_PRIVATE)
|
| {
|
| - gfc_error ("'%s' of '%s' is PRIVATE at %C", name, derived->name);
|
| + if (where)
|
| + gfc_error ("'%s' of '%s' is PRIVATE at %L",
|
| + gfc_op2string (op), derived->name, where);
|
| if (t)
|
| *t = FAILURE;
|
| }
|
| @@ -4335,9 +4969,32 @@ gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
|
| gfc_symbol* super_type;
|
| super_type = gfc_get_derived_super_type (derived);
|
| gcc_assert (super_type);
|
| - return gfc_find_typebound_proc (super_type, t, name, noaccess);
|
| +
|
| + return gfc_find_typebound_intrinsic_op (super_type, t, op,
|
| + noaccess, where);
|
| }
|
|
|
| /* Nothing found. */
|
| return NULL;
|
| }
|
| +
|
| +
|
| +/* Get a typebound-procedure symtree or create and insert it if not yet
|
| + present. This is like a very simplified version of gfc_get_sym_tree for
|
| + tbp-symtrees rather than regular ones. */
|
| +
|
| +gfc_symtree*
|
| +gfc_get_tbp_symtree (gfc_symtree **root, const char *name)
|
| +{
|
| + gfc_symtree *result;
|
| +
|
| + result = gfc_find_symtree (*root, name);
|
| + if (!result)
|
| + {
|
| + result = gfc_new_symtree (root, name);
|
| + gcc_assert (result);
|
| + result->n.tb = NULL;
|
| + }
|
| +
|
| + return result;
|
| +}
|
|
|