diff options
Diffstat (limited to 'gcc/fortran/symbol.c')
-rw-r--r-- | gcc/fortran/symbol.c | 5251 |
1 files changed, 0 insertions, 5251 deletions
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c deleted file mode 100644 index 1a4b022..0000000 --- a/gcc/fortran/symbol.c +++ /dev/null @@ -1,5251 +0,0 @@ -/* Maintain binary trees of symbols. - Copyright (C) 2000-2022 Free Software Foundation, Inc. - Contributed by Andy Vaught - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "options.h" -#include "gfortran.h" -#include "parse.h" -#include "match.h" -#include "constructor.h" - - -/* Strings for all symbol attributes. We use these for dumping the - parse tree, in error messages, and also when reading and writing - modules. */ - -const mstring flavors[] = -{ - minit ("UNKNOWN-FL", FL_UNKNOWN), minit ("PROGRAM", FL_PROGRAM), - minit ("BLOCK-DATA", FL_BLOCK_DATA), minit ("MODULE", FL_MODULE), - 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) -}; - -const mstring procedures[] = -{ - minit ("UNKNOWN-PROC", PROC_UNKNOWN), - minit ("MODULE-PROC", PROC_MODULE), - minit ("INTERNAL-PROC", PROC_INTERNAL), - minit ("DUMMY-PROC", PROC_DUMMY), - minit ("INTRINSIC-PROC", PROC_INTRINSIC), - minit ("EXTERNAL-PROC", PROC_EXTERNAL), - minit ("STATEMENT-PROC", PROC_ST_FUNCTION), - minit (NULL, -1) -}; - -const mstring intents[] = -{ - minit ("UNKNOWN-INTENT", INTENT_UNKNOWN), - minit ("IN", INTENT_IN), - minit ("OUT", INTENT_OUT), - minit ("INOUT", INTENT_INOUT), - minit (NULL, -1) -}; - -const mstring access_types[] = -{ - minit ("UNKNOWN-ACCESS", ACCESS_UNKNOWN), - minit ("PUBLIC", ACCESS_PUBLIC), - minit ("PRIVATE", ACCESS_PRIVATE), - minit (NULL, -1) -}; - -const mstring ifsrc_types[] = -{ - minit ("UNKNOWN", IFSRC_UNKNOWN), - minit ("DECL", IFSRC_DECL), - minit ("BODY", IFSRC_IFBODY) -}; - -const mstring save_status[] = -{ - minit ("UNKNOWN", SAVE_NONE), - minit ("EXPLICIT-SAVE", SAVE_EXPLICIT), - minit ("IMPLICIT-SAVE", SAVE_IMPLICIT), -}; - -/* Set the mstrings for DTIO procedure names. */ -const mstring dtio_procs[] = -{ - minit ("_dtio_formatted_read", DTIO_RF), - minit ("_dtio_formatted_write", DTIO_WF), - minit ("_dtio_unformatted_read", DTIO_RUF), - minit ("_dtio_unformatted_write", DTIO_WUF), -}; - -/* This is to make sure the backend generates setup code in the correct - order. */ - -static int next_dummy_order = 1; - - -gfc_namespace *gfc_current_ns; -gfc_namespace *gfc_global_ns_list; - -gfc_gsymbol *gfc_gsym_root = NULL; - -gfc_symbol *gfc_derived_types; - -static gfc_undo_change_set default_undo_chgset_var = { vNULL, vNULL, NULL }; -static gfc_undo_change_set *latest_undo_chgset = &default_undo_chgset_var; - - -/*********** IMPLICIT NONE and IMPLICIT statement handlers ***********/ - -/* The following static variable indicates whether a particular element has - been explicitly set or not. */ - -static int new_flag[GFC_LETTERS]; - - -/* Handle a correctly parsed IMPLICIT NONE. */ - -void -gfc_set_implicit_none (bool type, bool external, locus *loc) -{ - int i; - - if (external) - gfc_current_ns->has_implicit_none_export = 1; - - if (type) - { - gfc_current_ns->seen_implicit_none = 1; - for (i = 0; i < GFC_LETTERS; i++) - { - if (gfc_current_ns->set_flag[i]) - { - gfc_error_now ("IMPLICIT NONE (type) statement at %L following an " - "IMPLICIT statement", loc); - return; - } - gfc_clear_ts (&gfc_current_ns->default_type[i]); - gfc_current_ns->set_flag[i] = 1; - } - } -} - - -/* Reset the implicit range flags. */ - -void -gfc_clear_new_implicit (void) -{ - int i; - - for (i = 0; i < GFC_LETTERS; i++) - new_flag[i] = 0; -} - - -/* Prepare for a new implicit range. Sets flags in new_flag[]. */ - -bool -gfc_add_new_implicit_range (int c1, int c2) -{ - int i; - - c1 -= 'a'; - c2 -= 'a'; - - for (i = c1; i <= c2; i++) - { - if (new_flag[i]) - { - gfc_error ("Letter %qc already set in IMPLICIT statement at %C", - i + 'A'); - return false; - } - - new_flag[i] = 1; - } - - return true; -} - - -/* Add a matched implicit range for gfc_set_implicit(). Check if merging - the new implicit types back into the existing types will work. */ - -bool -gfc_merge_new_implicit (gfc_typespec *ts) -{ - int i; - - if (gfc_current_ns->seen_implicit_none) - { - gfc_error ("Cannot specify IMPLICIT at %C after IMPLICIT NONE"); - return false; - } - - for (i = 0; i < GFC_LETTERS; i++) - { - if (new_flag[i]) - { - if (gfc_current_ns->set_flag[i]) - { - gfc_error ("Letter %qc already has an IMPLICIT type at %C", - i + 'A'); - return false; - } - - gfc_current_ns->default_type[i] = *ts; - gfc_current_ns->implicit_loc[i] = gfc_current_locus; - gfc_current_ns->set_flag[i] = 1; - } - } - return true; -} - - -/* Given a symbol, return a pointer to the typespec for its default type. */ - -gfc_typespec * -gfc_get_default_type (const char *name, gfc_namespace *ns) -{ - char letter; - - letter = name[0]; - - if (flag_allow_leading_underscore && letter == '_') - gfc_fatal_error ("Option %<-fallow-leading-underscore%> is for use only by " - "gfortran developers, and should not be used for " - "implicitly typed variables"); - - if (letter < 'a' || letter > 'z') - gfc_internal_error ("gfc_get_default_type(): Bad symbol %qs", name); - - if (ns == NULL) - ns = gfc_current_ns; - - return &ns->default_type[letter - 'a']; -} - - -/* Recursively append candidate SYM to CANDIDATES. Store the number of - candidates in CANDIDATES_LEN. */ - -static void -lookup_symbol_fuzzy_find_candidates (gfc_symtree *sym, - char **&candidates, - size_t &candidates_len) -{ - gfc_symtree *p; - - if (sym == NULL) - return; - - if (sym->n.sym->ts.type != BT_UNKNOWN && sym->n.sym->ts.type != BT_PROCEDURE) - vec_push (candidates, candidates_len, sym->name); - p = sym->left; - if (p) - lookup_symbol_fuzzy_find_candidates (p, candidates, candidates_len); - - p = sym->right; - if (p) - lookup_symbol_fuzzy_find_candidates (p, candidates, candidates_len); -} - - -/* Lookup symbol SYM_NAME fuzzily, taking names in SYMBOL into account. */ - -static const char* -lookup_symbol_fuzzy (const char *sym_name, gfc_symbol *symbol) -{ - char **candidates = NULL; - size_t candidates_len = 0; - lookup_symbol_fuzzy_find_candidates (symbol->ns->sym_root, candidates, - candidates_len); - return gfc_closest_fuzzy_match (sym_name, candidates); -} - - -/* Given a pointer to a symbol, set its type according to the first - letter of its name. Fails if the letter in question has no default - type. */ - -bool -gfc_set_default_type (gfc_symbol *sym, int error_flag, gfc_namespace *ns) -{ - gfc_typespec *ts; - - if (sym->ts.type != BT_UNKNOWN) - gfc_internal_error ("gfc_set_default_type(): symbol already has a type"); - - ts = gfc_get_default_type (sym->name, ns); - - if (ts->type == BT_UNKNOWN) - { - if (error_flag && !sym->attr.untyped && !gfc_query_suppress_errors ()) - { - const char *guessed = lookup_symbol_fuzzy (sym->name, sym); - if (guessed) - gfc_error ("Symbol %qs at %L has no IMPLICIT type" - "; did you mean %qs?", - sym->name, &sym->declared_at, guessed); - else - gfc_error ("Symbol %qs at %L has no IMPLICIT type", - sym->name, &sym->declared_at); - sym->attr.untyped = 1; /* Ensure we only give an error once. */ - } - - return false; - } - - sym->ts = *ts; - sym->attr.implicit_type = 1; - - if (ts->type == BT_CHARACTER && ts->u.cl) - sym->ts.u.cl = gfc_new_charlen (sym->ns, ts->u.cl); - else if (ts->type == BT_CLASS - && !gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as)) - return false; - - if (sym->attr.is_bind_c == 1 && warn_c_binding_type) - { - /* BIND(C) variables should not be implicitly declared. */ - gfc_warning_now (OPT_Wc_binding_type, "Implicitly declared BIND(C) " - "variable %qs at %L may not be C interoperable", - sym->name, &sym->declared_at); - sym->ts.f90_type = sym->ts.type; - } - - if (sym->attr.dummy != 0) - { - if (sym->ns->proc_name != NULL - && (sym->ns->proc_name->attr.subroutine != 0 - || sym->ns->proc_name->attr.function != 0) - && sym->ns->proc_name->attr.is_bind_c != 0 - && warn_c_binding_type) - { - /* Dummy args to a BIND(C) routine may not be interoperable if - they are implicitly typed. */ - gfc_warning_now (OPT_Wc_binding_type, "Implicitly declared variable " - "%qs at %L may not be C interoperable but it is a " - "dummy argument to the BIND(C) procedure %qs at %L", - sym->name, &(sym->declared_at), - sym->ns->proc_name->name, - &(sym->ns->proc_name->declared_at)); - sym->ts.f90_type = sym->ts.type; - } - } - - return true; -} - - -/* This function is called from parse.c(parse_progunit) to check the - type of the function is not implicitly typed in the host namespace - and to implicitly type the function result, if necessary. */ - -void -gfc_check_function_type (gfc_namespace *ns) -{ - gfc_symbol *proc = ns->proc_name; - - if (!proc->attr.contained || proc->result->attr.implicit_type) - return; - - if (proc->result->ts.type == BT_UNKNOWN && proc->result->ts.interface == NULL) - { - if (gfc_set_default_type (proc->result, 0, gfc_current_ns)) - { - if (proc->result != proc) - { - proc->ts = proc->result->ts; - proc->as = gfc_copy_array_spec (proc->result->as); - proc->attr.dimension = proc->result->attr.dimension; - proc->attr.pointer = proc->result->attr.pointer; - proc->attr.allocatable = proc->result->attr.allocatable; - } - } - else if (!proc->result->attr.proc_pointer) - { - gfc_error ("Function result %qs at %L has no IMPLICIT type", - proc->result->name, &proc->result->declared_at); - proc->result->attr.untyped = 1; - } - } -} - - -/******************** Symbol attribute stuff *********************/ - -/* This is a generic conflict-checker. We do this to avoid having a - single conflict in two places. */ - -#define conf(a, b) if (attr->a && attr->b) { a1 = a; a2 = b; goto conflict; } -#define conf2(a) if (attr->a) { a2 = a; goto conflict; } -#define conf_std(a, b, std) if (attr->a && attr->b)\ - {\ - a1 = a;\ - a2 = b;\ - standard = std;\ - goto conflict_std;\ - } - -bool -gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where) -{ - static const char *dummy = "DUMMY", *save = "SAVE", *pointer = "POINTER", - *target = "TARGET", *external = "EXTERNAL", *intent = "INTENT", - *intent_in = "INTENT(IN)", *intrinsic = "INTRINSIC", - *intent_out = "INTENT(OUT)", *intent_inout = "INTENT(INOUT)", - *allocatable = "ALLOCATABLE", *elemental = "ELEMENTAL", - *privat = "PRIVATE", *recursive = "RECURSIVE", - *in_common = "COMMON", *result = "RESULT", *in_namelist = "NAMELIST", - *publik = "PUBLIC", *optional = "OPTIONAL", *entry = "ENTRY", - *function = "FUNCTION", *subroutine = "SUBROUTINE", - *dimension = "DIMENSION", *in_equivalence = "EQUIVALENCE", - *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", - *proc_pointer = "PROCEDURE POINTER", *abstract = "ABSTRACT", - *asynchronous = "ASYNCHRONOUS", *codimension = "CODIMENSION", - *contiguous = "CONTIGUOUS", *generic = "GENERIC", *automatic = "AUTOMATIC", - *pdt_len = "LEN", *pdt_kind = "KIND"; - static const char *threadprivate = "THREADPRIVATE"; - static const char *omp_declare_target = "OMP DECLARE TARGET"; - static const char *omp_declare_target_link = "OMP DECLARE TARGET LINK"; - static const char *oacc_declare_copyin = "OACC DECLARE COPYIN"; - static const char *oacc_declare_create = "OACC DECLARE CREATE"; - static const char *oacc_declare_deviceptr = "OACC DECLARE DEVICEPTR"; - static const char *oacc_declare_device_resident = - "OACC DECLARE DEVICE_RESIDENT"; - - const char *a1, *a2; - int standard; - - if (attr->artificial) - return true; - - if (where == NULL) - where = &gfc_current_locus; - - if (attr->pointer && attr->intent != INTENT_UNKNOWN) - { - a1 = pointer; - a2 = intent; - standard = GFC_STD_F2003; - goto conflict_std; - } - - if (attr->in_namelist && (attr->allocatable || attr->pointer)) - { - a1 = in_namelist; - a2 = attr->allocatable ? allocatable : pointer; - standard = GFC_STD_F2003; - goto conflict_std; - } - - /* Check for attributes not allowed in a BLOCK DATA. */ - if (gfc_current_state () == COMP_BLOCK_DATA) - { - a1 = NULL; - - if (attr->in_namelist) - a1 = in_namelist; - if (attr->allocatable) - a1 = allocatable; - if (attr->external) - a1 = external; - if (attr->optional) - a1 = optional; - if (attr->access == ACCESS_PRIVATE) - a1 = privat; - if (attr->access == ACCESS_PUBLIC) - a1 = publik; - if (attr->intent != INTENT_UNKNOWN) - a1 = intent; - - if (a1 != NULL) - { - gfc_error - ("%s attribute not allowed in BLOCK DATA program unit at %L", - a1, where); - return false; - } - } - - if (attr->save == SAVE_EXPLICIT) - { - conf (dummy, save); - conf (in_common, save); - conf (result, save); - conf (automatic, save); - - switch (attr->flavor) - { - case FL_PROGRAM: - case FL_BLOCK_DATA: - case FL_MODULE: - case FL_LABEL: - case_fl_struct: - case FL_PARAMETER: - a1 = gfc_code2string (flavors, attr->flavor); - a2 = save; - goto conflict; - case FL_NAMELIST: - gfc_error ("Namelist group name at %L cannot have the " - "SAVE attribute", where); - return false; - case FL_PROCEDURE: - /* Conflicts between SAVE and PROCEDURE will be checked at - resolution stage, see "resolve_fl_procedure". */ - case FL_VARIABLE: - default: - break; - } - } - - /* The copying of procedure dummy arguments for module procedures in - a submodule occur whilst the current state is COMP_CONTAINS. It - is necessary, therefore, to let this through. */ - if (name && attr->dummy - && (attr->function || attr->subroutine) - && gfc_current_state () == COMP_CONTAINS - && !(gfc_new_block && gfc_new_block->abr_modproc_decl)) - gfc_error_now ("internal procedure %qs at %L conflicts with " - "DUMMY argument", name, where); - - conf (dummy, entry); - conf (dummy, intrinsic); - conf (dummy, threadprivate); - conf (dummy, omp_declare_target); - conf (dummy, omp_declare_target_link); - conf (pointer, target); - conf (pointer, intrinsic); - conf (pointer, elemental); - conf (pointer, codimension); - conf (allocatable, elemental); - - conf (in_common, automatic); - conf (result, automatic); - conf (use_assoc, automatic); - conf (dummy, automatic); - - conf (target, external); - conf (target, intrinsic); - - if (!attr->if_source) - conf (external, dimension); /* See Fortran 95's R504. */ - - conf (external, intrinsic); - conf (entry, intrinsic); - conf (abstract, intrinsic); - - if ((attr->if_source == IFSRC_DECL && !attr->procedure) || attr->contained) - conf (external, subroutine); - - if (attr->proc_pointer && !gfc_notify_std (GFC_STD_F2003, - "Procedure pointer at %C")) - return false; - - conf (allocatable, pointer); - conf_std (allocatable, dummy, GFC_STD_F2003); - conf_std (allocatable, function, GFC_STD_F2003); - conf_std (allocatable, result, GFC_STD_F2003); - conf_std (elemental, recursive, GFC_STD_F2018); - - conf (in_common, dummy); - conf (in_common, allocatable); - conf (in_common, codimension); - conf (in_common, result); - - conf (in_equivalence, use_assoc); - conf (in_equivalence, codimension); - conf (in_equivalence, dummy); - conf (in_equivalence, target); - conf (in_equivalence, pointer); - conf (in_equivalence, function); - conf (in_equivalence, result); - conf (in_equivalence, entry); - conf (in_equivalence, allocatable); - conf (in_equivalence, threadprivate); - conf (in_equivalence, omp_declare_target); - conf (in_equivalence, omp_declare_target_link); - conf (in_equivalence, oacc_declare_create); - conf (in_equivalence, oacc_declare_copyin); - conf (in_equivalence, oacc_declare_deviceptr); - conf (in_equivalence, oacc_declare_device_resident); - conf (in_equivalence, is_bind_c); - - conf (dummy, result); - conf (entry, result); - conf (generic, result); - conf (generic, omp_declare_target); - conf (generic, omp_declare_target_link); - - conf (function, subroutine); - - if (!function && !subroutine) - conf (is_bind_c, dummy); - - conf (is_bind_c, cray_pointer); - conf (is_bind_c, cray_pointee); - conf (is_bind_c, codimension); - conf (is_bind_c, allocatable); - conf (is_bind_c, elemental); - - /* Need to also get volatile attr, according to 5.1 of F2003 draft. - Parameter conflict caught below. Also, value cannot be specified - for a dummy procedure. */ - - /* Cray pointer/pointee conflicts. */ - conf (cray_pointer, cray_pointee); - conf (cray_pointer, dimension); - conf (cray_pointer, codimension); - conf (cray_pointer, contiguous); - conf (cray_pointer, pointer); - conf (cray_pointer, target); - conf (cray_pointer, allocatable); - conf (cray_pointer, external); - conf (cray_pointer, intrinsic); - conf (cray_pointer, in_namelist); - conf (cray_pointer, function); - conf (cray_pointer, subroutine); - conf (cray_pointer, entry); - - conf (cray_pointee, allocatable); - conf (cray_pointee, contiguous); - conf (cray_pointee, codimension); - conf (cray_pointee, intent); - conf (cray_pointee, optional); - conf (cray_pointee, dummy); - conf (cray_pointee, target); - conf (cray_pointee, intrinsic); - conf (cray_pointee, pointer); - conf (cray_pointee, entry); - conf (cray_pointee, in_common); - conf (cray_pointee, in_equivalence); - conf (cray_pointee, threadprivate); - conf (cray_pointee, omp_declare_target); - conf (cray_pointee, omp_declare_target_link); - conf (cray_pointee, oacc_declare_create); - conf (cray_pointee, oacc_declare_copyin); - conf (cray_pointee, oacc_declare_deviceptr); - conf (cray_pointee, oacc_declare_device_resident); - - conf (data, dummy); - conf (data, function); - conf (data, result); - conf (data, allocatable); - - conf (value, pointer) - conf (value, allocatable) - conf (value, subroutine) - conf (value, function) - conf (value, volatile_) - conf (value, dimension) - conf (value, codimension) - conf (value, external) - - conf (codimension, result) - - if (attr->value - && (attr->intent == INTENT_OUT || attr->intent == INTENT_INOUT)) - { - a1 = value; - a2 = attr->intent == INTENT_OUT ? intent_out : intent_inout; - goto conflict; - } - - conf (is_protected, intrinsic) - conf (is_protected, in_common) - - conf (asynchronous, intrinsic) - conf (asynchronous, external) - - conf (volatile_, intrinsic) - conf (volatile_, external) - - if (attr->volatile_ && attr->intent == INTENT_IN) - { - a1 = volatile_; - a2 = intent_in; - goto conflict; - } - - conf (procedure, allocatable) - conf (procedure, dimension) - conf (procedure, codimension) - conf (procedure, intrinsic) - conf (procedure, target) - conf (procedure, value) - conf (procedure, volatile_) - conf (procedure, asynchronous) - conf (procedure, entry) - - conf (proc_pointer, abstract) - conf (proc_pointer, omp_declare_target) - conf (proc_pointer, omp_declare_target_link) - - conf (entry, omp_declare_target) - conf (entry, omp_declare_target_link) - conf (entry, oacc_declare_create) - conf (entry, oacc_declare_copyin) - conf (entry, oacc_declare_deviceptr) - conf (entry, oacc_declare_device_resident) - - conf (pdt_kind, allocatable) - conf (pdt_kind, pointer) - conf (pdt_kind, dimension) - conf (pdt_kind, codimension) - - conf (pdt_len, allocatable) - conf (pdt_len, pointer) - conf (pdt_len, dimension) - conf (pdt_len, codimension) - conf (pdt_len, pdt_kind) - - if (attr->access == ACCESS_PRIVATE) - { - a1 = privat; - conf2 (pdt_kind); - conf2 (pdt_len); - } - - a1 = gfc_code2string (flavors, attr->flavor); - - if (attr->in_namelist - && attr->flavor != FL_VARIABLE - && attr->flavor != FL_PROCEDURE - && attr->flavor != FL_UNKNOWN) - { - a2 = in_namelist; - goto conflict; - } - - switch (attr->flavor) - { - case FL_PROGRAM: - case FL_BLOCK_DATA: - case FL_MODULE: - case FL_LABEL: - conf2 (codimension); - conf2 (dimension); - conf2 (dummy); - conf2 (volatile_); - conf2 (asynchronous); - conf2 (contiguous); - conf2 (pointer); - conf2 (is_protected); - conf2 (target); - conf2 (external); - conf2 (intrinsic); - conf2 (allocatable); - conf2 (result); - conf2 (in_namelist); - conf2 (optional); - conf2 (function); - conf2 (subroutine); - conf2 (threadprivate); - conf2 (omp_declare_target); - conf2 (omp_declare_target_link); - conf2 (oacc_declare_create); - conf2 (oacc_declare_copyin); - conf2 (oacc_declare_deviceptr); - conf2 (oacc_declare_device_resident); - - if (attr->access == ACCESS_PUBLIC || attr->access == ACCESS_PRIVATE) - { - a2 = attr->access == ACCESS_PUBLIC ? publik : privat; - gfc_error ("%s attribute applied to %s %s at %L", a2, a1, - name, where); - return false; - } - - if (attr->is_bind_c) - { - gfc_error_now ("BIND(C) applied to %s %s at %L", a1, name, where); - return false; - } - - break; - - case FL_VARIABLE: - break; - - case FL_NAMELIST: - conf2 (result); - break; - - case 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 (volatile_); - conf2 (asynchronous); - conf2 (in_namelist); - conf2 (codimension); - conf2 (dimension); - conf2 (function); - if (!attr->proc_pointer) - conf2 (threadprivate); - } - - /* Procedure pointers in COMMON blocks are allowed in F03, - * but forbidden per F08:C5100. */ - if (!attr->proc_pointer || (gfc_option.allow_std & GFC_STD_F2008)) - conf2 (in_common); - - conf2 (omp_declare_target_link); - - switch (attr->proc) - { - case PROC_ST_FUNCTION: - conf2 (dummy); - conf2 (target); - break; - - case PROC_MODULE: - conf2 (dummy); - break; - - case PROC_DUMMY: - conf2 (result); - conf2 (threadprivate); - break; - - default: - break; - } - - break; - - case_fl_struct: - conf2 (dummy); - conf2 (pointer); - conf2 (target); - conf2 (external); - conf2 (intrinsic); - conf2 (allocatable); - conf2 (optional); - conf2 (entry); - conf2 (function); - conf2 (subroutine); - conf2 (threadprivate); - conf2 (result); - conf2 (omp_declare_target); - conf2 (omp_declare_target_link); - conf2 (oacc_declare_create); - conf2 (oacc_declare_copyin); - conf2 (oacc_declare_deviceptr); - conf2 (oacc_declare_device_resident); - - if (attr->intent != INTENT_UNKNOWN) - { - a2 = intent; - goto conflict; - } - break; - - case FL_PARAMETER: - conf2 (external); - conf2 (intrinsic); - conf2 (optional); - conf2 (allocatable); - conf2 (function); - conf2 (subroutine); - conf2 (entry); - conf2 (contiguous); - conf2 (pointer); - conf2 (is_protected); - conf2 (target); - conf2 (dummy); - conf2 (in_common); - conf2 (value); - conf2 (volatile_); - conf2 (asynchronous); - conf2 (threadprivate); - conf2 (value); - conf2 (codimension); - conf2 (result); - if (!attr->is_iso_c) - conf2 (is_bind_c); - break; - - default: - break; - } - - return true; - -conflict: - if (name == NULL) - gfc_error ("%s attribute conflicts with %s attribute at %L", - a1, a2, where); - else - gfc_error ("%s attribute conflicts with %s attribute in %qs at %L", - a1, a2, name, where); - - return false; - -conflict_std: - if (name == NULL) - { - return gfc_notify_std (standard, "%s attribute conflicts " - "with %s attribute at %L", a1, a2, - where); - } - else - { - return gfc_notify_std (standard, "%s attribute conflicts " - "with %s attribute in %qs at %L", - a1, a2, name, where); - } -} - -#undef conf -#undef conf2 -#undef conf_std - - -/* Mark a symbol as referenced. */ - -void -gfc_set_sym_referenced (gfc_symbol *sym) -{ - - if (sym->attr.referenced) - return; - - sym->attr.referenced = 1; - - /* Remember which order dummy variables are accessed in. */ - if (sym->attr.dummy) - sym->dummy_order = next_dummy_order++; -} - - -/* Common subroutine called by attribute changing subroutines in order - to prevent them from changing a symbol that has been - use-associated. Returns zero if it is OK to change the symbol, - nonzero if not. */ - -static int -check_used (symbol_attribute *attr, const char *name, locus *where) -{ - - if (attr->use_assoc == 0) - return 0; - - if (where == NULL) - where = &gfc_current_locus; - - if (name == NULL) - gfc_error ("Cannot change attributes of USE-associated symbol at %L", - where); - else - gfc_error ("Cannot change attributes of USE-associated symbol %s at %L", - name, where); - - return 1; -} - - -/* Generate an error because of a duplicate attribute. */ - -static void -duplicate_attr (const char *attr, locus *where) -{ - - if (where == NULL) - where = &gfc_current_locus; - - gfc_error ("Duplicate %s attribute specified at %L", attr, where); -} - - -bool -gfc_add_ext_attribute (symbol_attribute *attr, ext_attr_id_t ext_attr, - locus *where ATTRIBUTE_UNUSED) -{ - attr->ext_attr |= 1 << ext_attr; - return true; -} - - -/* Called from decl.c (attr_decl1) to check attributes, when declared - separately. */ - -bool -gfc_add_attribute (symbol_attribute *attr, locus *where) -{ - if (check_used (attr, NULL, where)) - return false; - - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_allocatable (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->allocatable && ! gfc_submodule_procedure(attr)) - { - duplicate_attr ("ALLOCATABLE", where); - return false; - } - - if (attr->flavor == FL_PROCEDURE && attr->if_source == IFSRC_IFBODY - && !gfc_find_state (COMP_INTERFACE)) - { - gfc_error ("ALLOCATABLE specified outside of INTERFACE body at %L", - where); - return false; - } - - attr->allocatable = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_automatic (symbol_attribute *attr, const char *name, locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->automatic && !gfc_notify_std (GFC_STD_LEGACY, - "Duplicate AUTOMATIC attribute specified at %L", where)) - return false; - - attr->automatic = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_codimension (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->codimension) - { - duplicate_attr ("CODIMENSION", where); - return false; - } - - if (attr->flavor == FL_PROCEDURE && attr->if_source == IFSRC_IFBODY - && !gfc_find_state (COMP_INTERFACE)) - { - gfc_error ("CODIMENSION specified for %qs outside its INTERFACE body " - "at %L", name, where); - return false; - } - - attr->codimension = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_dimension (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->dimension && ! gfc_submodule_procedure(attr)) - { - duplicate_attr ("DIMENSION", where); - return false; - } - - if (attr->flavor == FL_PROCEDURE && attr->if_source == IFSRC_IFBODY - && !gfc_find_state (COMP_INTERFACE)) - { - gfc_error ("DIMENSION specified for %qs outside its INTERFACE body " - "at %L", name, where); - return false; - } - - attr->dimension = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_contiguous (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - attr->contiguous = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_external (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->external) - { - duplicate_attr ("EXTERNAL", where); - return false; - } - - if (attr->pointer && attr->if_source != IFSRC_IFBODY) - { - attr->pointer = 0; - attr->proc_pointer = 1; - } - - attr->external = 1; - - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_intrinsic (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->intrinsic) - { - duplicate_attr ("INTRINSIC", where); - return false; - } - - attr->intrinsic = 1; - - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_optional (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->optional) - { - duplicate_attr ("OPTIONAL", where); - return false; - } - - attr->optional = 1; - return gfc_check_conflict (attr, NULL, where); -} - -bool -gfc_add_kind (symbol_attribute *attr, locus *where) -{ - if (attr->pdt_kind) - { - duplicate_attr ("KIND", where); - return false; - } - - attr->pdt_kind = 1; - return gfc_check_conflict (attr, NULL, where); -} - -bool -gfc_add_len (symbol_attribute *attr, locus *where) -{ - if (attr->pdt_len) - { - duplicate_attr ("LEN", where); - return false; - } - - attr->pdt_len = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_pointer (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->pointer && !(attr->if_source == IFSRC_IFBODY - && !gfc_find_state (COMP_INTERFACE)) - && ! gfc_submodule_procedure(attr)) - { - duplicate_attr ("POINTER", where); - return false; - } - - if (attr->procedure || (attr->external && attr->if_source != IFSRC_IFBODY) - || (attr->if_source == IFSRC_IFBODY - && !gfc_find_state (COMP_INTERFACE))) - attr->proc_pointer = 1; - else - attr->pointer = 1; - - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_cray_pointer (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - attr->cray_pointer = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_cray_pointee (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->cray_pointee) - { - gfc_error ("Cray Pointee at %L appears in multiple pointer()" - " statements", where); - return false; - } - - attr->cray_pointee = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_protected (symbol_attribute *attr, const char *name, locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->is_protected) - { - if (!gfc_notify_std (GFC_STD_LEGACY, - "Duplicate PROTECTED attribute specified at %L", - where)) - return false; - } - - attr->is_protected = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_result (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - attr->result = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_save (symbol_attribute *attr, save_state s, const char *name, - locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (s == SAVE_EXPLICIT && gfc_pure (NULL)) - { - gfc_error - ("SAVE attribute at %L cannot be specified in a PURE procedure", - where); - return false; - } - - if (s == SAVE_EXPLICIT) - gfc_unset_implicit_pure (NULL); - - if (s == SAVE_EXPLICIT && attr->save == SAVE_EXPLICIT - && (flag_automatic || pedantic)) - { - if (!gfc_notify_std (GFC_STD_LEGACY, - "Duplicate SAVE attribute specified at %L", - where)) - return false; - } - - attr->save = s; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_value (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->value) - { - if (!gfc_notify_std (GFC_STD_LEGACY, - "Duplicate VALUE attribute specified at %L", - where)) - return false; - } - - attr->value = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_volatile (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 VOLATILE attribute - unless it is a coarray (F2008, C560). */ - - if (attr->volatile_ && attr->volatile_ns == gfc_current_ns) - if (!gfc_notify_std (GFC_STD_LEGACY, - "Duplicate VOLATILE attribute specified at %L", - where)) - return false; - - /* F2008: C1282 A designator of a variable with the VOLATILE attribute - shall not appear in a pure subprogram. - - F2018: C1588 A local variable of a pure subprogram, or of a BLOCK - construct within a pure subprogram, shall not have the SAVE or - VOLATILE attribute. */ - if (gfc_pure (NULL)) - { - gfc_error ("VOLATILE attribute at %L cannot be specified in a " - "PURE procedure", where); - return false; - } - - - attr->volatile_ = 1; - attr->volatile_ns = gfc_current_ns; - return gfc_check_conflict (attr, name, where); -} - - -bool -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)) - return false; - - attr->asynchronous = 1; - attr->asynchronous_ns = gfc_current_ns; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_threadprivate (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->threadprivate) - { - duplicate_attr ("THREADPRIVATE", where); - return false; - } - - attr->threadprivate = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_omp_declare_target (symbol_attribute *attr, const char *name, - locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->omp_declare_target) - return true; - - attr->omp_declare_target = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_omp_declare_target_link (symbol_attribute *attr, const char *name, - locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->omp_declare_target_link) - return true; - - attr->omp_declare_target_link = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_oacc_declare_create (symbol_attribute *attr, const char *name, - locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->oacc_declare_create) - return true; - - attr->oacc_declare_create = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_oacc_declare_copyin (symbol_attribute *attr, const char *name, - locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->oacc_declare_copyin) - return true; - - attr->oacc_declare_copyin = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_oacc_declare_deviceptr (symbol_attribute *attr, const char *name, - locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->oacc_declare_deviceptr) - return true; - - attr->oacc_declare_deviceptr = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_oacc_declare_device_resident (symbol_attribute *attr, const char *name, - locus *where) -{ - if (check_used (attr, name, where)) - return false; - - if (attr->oacc_declare_device_resident) - return true; - - attr->oacc_declare_device_resident = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_target (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->target) - { - duplicate_attr ("TARGET", where); - return false; - } - - attr->target = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_dummy (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - /* Duplicate dummy arguments are allowed due to ENTRY statements. */ - attr->dummy = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_in_common (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - /* Duplicate attribute already checked for. */ - attr->in_common = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_in_equivalence (symbol_attribute *attr, const char *name, locus *where) -{ - - /* Duplicate attribute already checked for. */ - attr->in_equivalence = 1; - if (!gfc_check_conflict (attr, name, where)) - return false; - - if (attr->flavor == FL_VARIABLE) - return true; - - return gfc_add_flavor (attr, FL_VARIABLE, name, where); -} - - -bool -gfc_add_data (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - attr->data = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_in_namelist (symbol_attribute *attr, const char *name, locus *where) -{ - - attr->in_namelist = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_sequence (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - attr->sequence = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_elemental (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->elemental) - { - duplicate_attr ("ELEMENTAL", where); - return false; - } - - attr->elemental = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_pure (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->pure) - { - duplicate_attr ("PURE", where); - return false; - } - - attr->pure = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_recursive (symbol_attribute *attr, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->recursive) - { - duplicate_attr ("RECURSIVE", where); - return false; - } - - attr->recursive = 1; - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_entry (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->entry) - { - duplicate_attr ("ENTRY", where); - return false; - } - - attr->entry = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_function (symbol_attribute *attr, const char *name, locus *where) -{ - - if (attr->flavor != FL_PROCEDURE - && !gfc_add_flavor (attr, FL_PROCEDURE, name, where)) - return false; - - attr->function = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_subroutine (symbol_attribute *attr, const char *name, locus *where) -{ - - if (attr->flavor != FL_PROCEDURE - && !gfc_add_flavor (attr, FL_PROCEDURE, name, where)) - return false; - - attr->subroutine = 1; - - /* If we are looking at a BLOCK DATA statement and we encounter a - name with a leading underscore (which must be - compiler-generated), do not check. See PR 84394. */ - - if (name && *name != '_' && gfc_current_state () != COMP_BLOCK_DATA) - return gfc_check_conflict (attr, name, where); - else - return true; -} - - -bool -gfc_add_generic (symbol_attribute *attr, const char *name, locus *where) -{ - - if (attr->flavor != FL_PROCEDURE - && !gfc_add_flavor (attr, FL_PROCEDURE, name, where)) - return false; - - attr->generic = 1; - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_proc (symbol_attribute *attr, const char *name, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->flavor != FL_PROCEDURE - && !gfc_add_flavor (attr, FL_PROCEDURE, name, where)) - return false; - - if (attr->procedure) - { - duplicate_attr ("PROCEDURE", where); - return false; - } - - attr->procedure = 1; - - return gfc_check_conflict (attr, NULL, where); -} - - -bool -gfc_add_abstract (symbol_attribute* attr, locus* where) -{ - if (attr->abstract) - { - duplicate_attr ("ABSTRACT", where); - return false; - } - - attr->abstract = 1; - - return gfc_check_conflict (attr, NULL, where); -} - - -/* Flavors are special because some flavors are not what Fortran - considers attributes and can be reaffirmed multiple times. */ - -bool -gfc_add_flavor (symbol_attribute *attr, sym_flavor f, const char *name, - locus *where) -{ - - if ((f == FL_PROGRAM || f == FL_BLOCK_DATA || f == FL_MODULE - || f == FL_PARAMETER || f == FL_LABEL || gfc_fl_struct(f) - || f == FL_NAMELIST) && check_used (attr, name, where)) - return false; - - if (attr->flavor == f && f == FL_VARIABLE) - return true; - - /* Copying a procedure dummy argument for a module procedure in a - submodule results in the flavor being copied and would result in - an error without this. */ - if (attr->flavor == f && f == FL_PROCEDURE - && gfc_new_block && gfc_new_block->abr_modproc_decl) - return true; - - if (attr->flavor != FL_UNKNOWN) - { - if (where == NULL) - where = &gfc_current_locus; - - if (name) - gfc_error ("%s attribute of %qs conflicts with %s attribute at %L", - gfc_code2string (flavors, attr->flavor), name, - gfc_code2string (flavors, f), where); - else - gfc_error ("%s attribute conflicts with %s attribute at %L", - gfc_code2string (flavors, attr->flavor), - gfc_code2string (flavors, f), where); - - return false; - } - - attr->flavor = f; - - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_procedure (symbol_attribute *attr, procedure_type t, - const char *name, locus *where) -{ - - if (check_used (attr, name, where)) - return false; - - if (attr->flavor != FL_PROCEDURE - && !gfc_add_flavor (attr, FL_PROCEDURE, name, where)) - return false; - - if (where == NULL) - where = &gfc_current_locus; - - if (attr->proc != PROC_UNKNOWN && !attr->module_procedure - && attr->access == ACCESS_UNKNOWN) - { - if (attr->proc == PROC_ST_FUNCTION && t == PROC_INTERNAL - && !gfc_notification_std (GFC_STD_F2008)) - gfc_error ("%s procedure at %L is already declared as %s " - "procedure. \nF2008: A pointer function assignment " - "is ambiguous if it is the first executable statement " - "after the specification block. Please add any other " - "kind of executable statement before it. FIXME", - gfc_code2string (procedures, t), where, - gfc_code2string (procedures, attr->proc)); - else - gfc_error ("%s procedure at %L is already declared as %s " - "procedure", gfc_code2string (procedures, t), where, - gfc_code2string (procedures, attr->proc)); - - return false; - } - - attr->proc = t; - - /* Statement functions are always scalar and functions. */ - if (t == PROC_ST_FUNCTION - && ((!attr->function && !gfc_add_function (attr, name, where)) - || attr->dimension)) - return false; - - return gfc_check_conflict (attr, name, where); -} - - -bool -gfc_add_intent (symbol_attribute *attr, sym_intent intent, locus *where) -{ - - if (check_used (attr, NULL, where)) - return false; - - if (attr->intent == INTENT_UNKNOWN) - { - attr->intent = intent; - return gfc_check_conflict (attr, NULL, where); - } - - if (where == NULL) - where = &gfc_current_locus; - - gfc_error ("INTENT (%s) conflicts with INTENT(%s) at %L", - gfc_intent_string (attr->intent), - gfc_intent_string (intent), where); - - return false; -} - - -/* No checks for use-association in public and private statements. */ - -bool -gfc_add_access (symbol_attribute *attr, gfc_access access, - const char *name, locus *where) -{ - - if (attr->access == ACCESS_UNKNOWN - || (attr->use_assoc && attr->access != ACCESS_PRIVATE)) - { - attr->access = access; - return gfc_check_conflict (attr, name, where); - } - - if (where == NULL) - where = &gfc_current_locus; - gfc_error ("ACCESS specification at %L was already specified", where); - - return false; -} - - -/* Set the is_bind_c field for the given symbol_attribute. */ - -bool -gfc_add_is_bind_c (symbol_attribute *attr, const char *name, locus *where, - int is_proc_lang_bind_spec) -{ - - if (is_proc_lang_bind_spec == 0 && attr->flavor == FL_PROCEDURE) - gfc_error_now ("BIND(C) attribute at %L can only be used for " - "variables or common blocks", where); - else if (attr->is_bind_c) - gfc_error_now ("Duplicate BIND attribute specified at %L", where); - else - attr->is_bind_c = 1; - - if (where == NULL) - where = &gfc_current_locus; - - if (!gfc_notify_std (GFC_STD_F2003, "BIND(C) at %L", where)) - return false; - - return gfc_check_conflict (attr, name, where); -} - - -/* Set the extension field for the given symbol_attribute. */ - -bool -gfc_add_extension (symbol_attribute *attr, locus *where) -{ - if (where == NULL) - where = &gfc_current_locus; - - if (attr->extension) - gfc_error_now ("Duplicate EXTENDS attribute specified at %L", where); - else - attr->extension = 1; - - if (!gfc_notify_std (GFC_STD_F2003, "EXTENDS at %L", where)) - return false; - - return true; -} - - -bool -gfc_add_explicit_interface (gfc_symbol *sym, ifsrc source, - gfc_formal_arglist * formal, locus *where) -{ - if (check_used (&sym->attr, sym->name, where)) - return false; - - /* Skip the following checks in the case of a module_procedures in a - submodule since they will manifestly fail. */ - if (sym->attr.module_procedure == 1 - && source == IFSRC_DECL) - goto finish; - - if (where == NULL) - where = &gfc_current_locus; - - if (sym->attr.if_source != IFSRC_UNKNOWN - && sym->attr.if_source != IFSRC_DECL) - { - gfc_error ("Symbol %qs at %L already has an explicit interface", - sym->name, where); - return false; - } - - if (source == IFSRC_IFBODY && (sym->attr.dimension || sym->attr.allocatable)) - { - gfc_error ("%qs at %L has attributes specified outside its INTERFACE " - "body", sym->name, where); - return false; - } - -finish: - sym->formal = formal; - sym->attr.if_source = source; - - return true; -} - - -/* Add a type to a symbol. */ - -bool -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->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) - && !(gfc_state_stack->previous && gfc_state_stack->previous->previous - && gfc_state_stack->previous->previous->state == COMP_SUBMODULE) - && !sym->attr.module_procedure) - { - if (sym->attr.use_assoc) - gfc_error ("Symbol %qs at %L conflicts with symbol from module %qs, " - "use-associated at %L", sym->name, where, sym->module, - &sym->declared_at); - else if (sym->attr.function && sym->attr.result) - gfc_error ("Symbol %qs at %L already has basic type of %s", - sym->ns->proc_name->name, where, gfc_basic_typename (type)); - else - gfc_error ("Symbol %qs at %L already has basic type of %s", sym->name, - where, gfc_basic_typename (type)); - return false; - } - - if (sym->attr.procedure && sym->ts.interface) - { - gfc_error ("Procedure %qs at %L may not have basic type of %s", - sym->name, where, gfc_basic_typename (ts->type)); - return false; - } - - flavor = sym->attr.flavor; - - if (flavor == FL_PROGRAM || flavor == FL_BLOCK_DATA || flavor == FL_MODULE - || flavor == FL_LABEL - || (flavor == FL_PROCEDURE && sym->attr.subroutine) - || flavor == FL_DERIVED || flavor == FL_NAMELIST) - { - gfc_error ("Symbol %qs at %L cannot have a type", - sym->ns->proc_name ? sym->ns->proc_name->name : sym->name, - where); - return false; - } - - sym->ts = *ts; - return true; -} - - -/* Clears all attributes. */ - -void -gfc_clear_attr (symbol_attribute *attr) -{ - memset (attr, 0, sizeof (symbol_attribute)); -} - - -/* Check for missing attributes in the new symbol. Currently does - nothing, but it's not clear that it is unnecessary yet. */ - -bool -gfc_missing_attr (symbol_attribute *attr ATTRIBUTE_UNUSED, - locus *where ATTRIBUTE_UNUSED) -{ - - return true; -} - - -/* Copy an attribute to a symbol attribute, bit by bit. Some - attributes have a lot of side-effects but cannot be present given - where we are called from, so we ignore some bits. */ - -bool -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)) - goto fail; - - if (src->automatic && !gfc_add_automatic (dest, NULL, where)) - goto fail; - if (src->dimension && !gfc_add_dimension (dest, NULL, where)) - goto fail; - if (src->codimension && !gfc_add_codimension (dest, NULL, where)) - goto fail; - if (src->contiguous && !gfc_add_contiguous (dest, NULL, where)) - goto fail; - if (src->optional && !gfc_add_optional (dest, where)) - goto fail; - if (src->pointer && !gfc_add_pointer (dest, where)) - goto fail; - if (src->is_protected && !gfc_add_protected (dest, NULL, where)) - goto fail; - if (src->save && !gfc_add_save (dest, src->save, NULL, where)) - goto fail; - if (src->value && !gfc_add_value (dest, NULL, where)) - goto fail; - if (src->volatile_ && !gfc_add_volatile (dest, NULL, where)) - goto fail; - if (src->asynchronous && !gfc_add_asynchronous (dest, NULL, where)) - goto fail; - if (src->threadprivate - && !gfc_add_threadprivate (dest, NULL, where)) - goto fail; - if (src->omp_declare_target - && !gfc_add_omp_declare_target (dest, NULL, where)) - goto fail; - if (src->omp_declare_target_link - && !gfc_add_omp_declare_target_link (dest, NULL, where)) - goto fail; - if (src->oacc_declare_create - && !gfc_add_oacc_declare_create (dest, NULL, where)) - goto fail; - if (src->oacc_declare_copyin - && !gfc_add_oacc_declare_copyin (dest, NULL, where)) - goto fail; - if (src->oacc_declare_deviceptr - && !gfc_add_oacc_declare_deviceptr (dest, NULL, where)) - goto fail; - if (src->oacc_declare_device_resident - && !gfc_add_oacc_declare_device_resident (dest, NULL, where)) - goto fail; - if (src->target && !gfc_add_target (dest, where)) - goto fail; - if (src->dummy && !gfc_add_dummy (dest, NULL, where)) - goto fail; - if (src->result && !gfc_add_result (dest, NULL, where)) - goto fail; - if (src->entry) - dest->entry = 1; - - if (src->in_namelist && !gfc_add_in_namelist (dest, NULL, where)) - goto fail; - - if (src->in_common && !gfc_add_in_common (dest, NULL, where)) - goto fail; - - if (src->generic && !gfc_add_generic (dest, NULL, where)) - goto fail; - if (src->function && !gfc_add_function (dest, NULL, where)) - goto fail; - if (src->subroutine && !gfc_add_subroutine (dest, NULL, where)) - goto fail; - - if (src->sequence && !gfc_add_sequence (dest, NULL, where)) - goto fail; - if (src->elemental && !gfc_add_elemental (dest, where)) - goto fail; - if (src->pure && !gfc_add_pure (dest, where)) - goto fail; - if (src->recursive && !gfc_add_recursive (dest, where)) - goto fail; - - if (src->flavor != FL_UNKNOWN - && !gfc_add_flavor (dest, src->flavor, NULL, where)) - goto fail; - - if (src->intent != INTENT_UNKNOWN - && !gfc_add_intent (dest, src->intent, where)) - goto fail; - - if (src->access != ACCESS_UNKNOWN - && !gfc_add_access (dest, src->access, NULL, where)) - goto fail; - - if (!gfc_missing_attr (dest, where)) - goto fail; - - if (src->cray_pointer && !gfc_add_cray_pointer (dest, where)) - goto fail; - if (src->cray_pointee && !gfc_add_cray_pointee (dest, where)) - goto fail; - - is_proc_lang_bind_spec = (src->flavor == FL_PROCEDURE ? 1 : 0); - if (src->is_bind_c - && !gfc_add_is_bind_c (dest, NULL, where, is_proc_lang_bind_spec)) - return false; - - if (src->is_c_interop) - dest->is_c_interop = 1; - if (src->is_iso_c) - dest->is_iso_c = 1; - - if (src->external && !gfc_add_external (dest, where)) - goto fail; - if (src->intrinsic && !gfc_add_intrinsic (dest, where)) - goto fail; - if (src->proc_pointer) - dest->proc_pointer = 1; - - return true; - -fail: - return false; -} - - -/* A function to generate a dummy argument symbol using that from the - interface declaration. Can be used for the result symbol as well if - the flag is set. */ - -int -gfc_copy_dummy_sym (gfc_symbol **dsym, gfc_symbol *sym, int result) -{ - int rc; - - rc = gfc_get_symbol (sym->name, NULL, dsym); - if (rc) - return rc; - - if (!gfc_add_type (*dsym, &(sym->ts), &gfc_current_locus)) - return 1; - - if (!gfc_copy_attr (&(*dsym)->attr, &(sym->attr), - &gfc_current_locus)) - return 1; - - if ((*dsym)->attr.dimension) - (*dsym)->as = gfc_copy_array_spec (sym->as); - - (*dsym)->attr.class_ok = sym->attr.class_ok; - - if ((*dsym) != NULL && !result - && (!gfc_add_dummy(&(*dsym)->attr, (*dsym)->name, NULL) - || !gfc_missing_attr (&(*dsym)->attr, NULL))) - return 1; - else if ((*dsym) != NULL && result - && (!gfc_add_result(&(*dsym)->attr, (*dsym)->name, NULL) - || !gfc_missing_attr (&(*dsym)->attr, NULL))) - return 1; - - return 0; -} - - -/************** Component name management ************/ - -/* Component names of a derived type form their own little namespaces - that are separate from all other spaces. The space is composed of - a singly linked list of gfc_component structures whose head is - located in the parent symbol. */ - - -/* Add a component name to a symbol. The call fails if the name is - already present. On success, the component pointer is modified to - point to the additional component structure. */ - -bool -gfc_add_component (gfc_symbol *sym, const char *name, - gfc_component **component) -{ - 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) - { - if (strcmp (p->name, name) == 0) - { - gfc_error ("Component %qs at %C already declared at %L", - name, &p->loc); - return false; - } - - tail = p; - } - - if (sym->attr.extension - && 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); - return false; - } - - /* Allocate a new component. */ - p = gfc_get_component (); - - if (tail == NULL) - sym->components = p; - else - tail->next = p; - - p->name = gfc_get_string ("%s", name); - p->loc = gfc_current_locus; - p->ts.type = BT_UNKNOWN; - - *component = p; - return true; -} - - -/* Recursive function to switch derived types of all symbol in a - namespace. */ - -static void -switch_types (gfc_symtree *st, gfc_symbol *from, gfc_symbol *to) -{ - gfc_symbol *sym; - - if (st == NULL) - return; - - sym = st->n.sym; - 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); -} - - -/* This subroutine is called when a derived type is used in order to - make the final determination about which version to use. The - standard requires that a type be defined before it is 'used', but - such types can appear in IMPLICIT statements before the actual - definition. 'Using' in this context means declaring a variable to - be that type or using the type constructor. - - If a type is used and the components haven't been defined, then we - have to have a derived type in a parent unit. We find the node in - the other namespace and point the symtree node in this namespace to - that node. Further reference to this name point to the correct - node. If we can't find the node in a parent namespace, then we have - an error. - - This subroutine takes a pointer to a symbol node and returns a - pointer to the translated node or NULL for an error. Usually there - is no translation and we return the node we were passed. */ - -gfc_symbol * -gfc_use_derived (gfc_symbol *sym) -{ - gfc_symbol *s; - gfc_typespec *t; - gfc_symtree *st; - int i; - - if (!sym) - return NULL; - - if (sym->attr.unlimited_polymorphic) - return sym; - - if (sym->attr.generic) - sym = gfc_find_dt_in_generic (sym); - - if (sym->components != NULL || sym->attr.zero_comp) - return sym; /* Already defined. */ - - if (sym->ns->parent == NULL) - goto bad; - - if (gfc_find_symbol (sym->name, sym->ns->parent, 1, &s)) - { - gfc_error ("Symbol %qs at %C is ambiguous", sym->name); - return NULL; - } - - if (s == NULL || !gfc_fl_struct (s->attr.flavor)) - goto bad; - - /* Get rid of symbol sym, translating all references to s. */ - for (i = 0; i < GFC_LETTERS; i++) - { - t = &sym->ns->default_type[i]; - if (t->u.derived == sym) - t->u.derived = s; - } - - st = gfc_find_symtree (sym->ns->sym_root, sym->name); - st->n.sym = s; - - s->refs++; - - /* Unlink from list of modified symbols. */ - gfc_commit_symbol (sym); - - switch_types (sym->ns->sym_root, sym, s); - - /* TODO: Also have to replace sym -> s in other lists like - namelists, common lists and interface lists. */ - gfc_free_symbol (sym); - - return s; - -bad: - gfc_error ("Derived type %qs at %C is being used before it is defined", - sym->name); - return NULL; -} - - -/* 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; -} - - -/* Recursively append candidate COMPONENT structures to CANDIDATES. Store - the number of total candidates in CANDIDATES_LEN. */ - -static void -lookup_component_fuzzy_find_candidates (gfc_component *component, - char **&candidates, - size_t &candidates_len) -{ - for (gfc_component *p = component; p; p = p->next) - vec_push (candidates, candidates_len, p->name); -} - - -/* Lookup component MEMBER fuzzily, taking names in COMPONENT into account. */ - -static const char* -lookup_component_fuzzy (const char *member, gfc_component *component) -{ - char **candidates = NULL; - size_t candidates_len = 0; - lookup_component_fuzzy_find_candidates (component, candidates, - candidates_len); - return gfc_closest_fuzzy_match (member, candidates); -} - - -/* 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. 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, gfc_ref **ref) -{ - gfc_component *p, *check; - gfc_ref *sref = NULL, *tmp = NULL; - - if (name == NULL || sym == NULL) - return NULL; - - 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) - { - /* 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) - { - 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 %qs at %C is a PRIVATE component of %qs", - name, sym->name); - return NULL; - } - } - - if (p == NULL - && sym->attr.extension - && sym->components->ts.type == BT_DERIVED) - { - p = gfc_find_component (sym->components->ts.u.derived, name, - noaccess, silent, ref); - /* Do not overwrite the error. */ - if (p == NULL) - return p; - } - - if (p == NULL && !silent) - { - const char *guessed = lookup_component_fuzzy (name, sym->components); - if (guessed) - gfc_error ("%qs at %C is not a member of the %qs structure" - "; did you mean %qs?", - name, sym->name, guessed); - else - 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; -} - - -/* Given a symbol, free all of the component structures and everything - they point to. */ - -static void -free_components (gfc_component *p) -{ - gfc_component *q; - - for (; p; p = q) - { - q = p->next; - - gfc_free_array_spec (p->as); - gfc_free_expr (p->initializer); - if (p->kind_expr) - gfc_free_expr (p->kind_expr); - if (p->param_list) - gfc_free_actual_arglist (p->param_list); - free (p->tb); - p->tb = NULL; - free (p); - } -} - - -/******************** Statement label management ********************/ - -/* Comparison function for statement labels, used for managing the - binary tree. */ - -static int -compare_st_labels (void *a1, void *b1) -{ - int a = ((gfc_st_label *) a1)->value; - int b = ((gfc_st_label *) b1)->value; - - return (b - a); -} - - -/* Free a single gfc_st_label structure, making sure the tree is not - messed up. This function is called only when some parse error - occurs. */ - -void -gfc_free_st_label (gfc_st_label *label) -{ - - if (label == NULL) - return; - - gfc_delete_bbt (&label->ns->st_labels, label, compare_st_labels); - - if (label->format != NULL) - gfc_free_expr (label->format); - - free (label); -} - - -/* Free a whole tree of gfc_st_label structures. */ - -static void -free_st_labels (gfc_st_label *label) -{ - - if (label == NULL) - return; - - free_st_labels (label->left); - free_st_labels (label->right); - - if (label->format != NULL) - gfc_free_expr (label->format); - free (label); -} - - -/* Given a label number, search for and return a pointer to the label - structure, creating it if it does not exist. */ - -gfc_st_label * -gfc_get_st_label (int labelno) -{ - gfc_st_label *lp; - gfc_namespace *ns; - - if (gfc_current_state () == COMP_DERIVED) - ns = gfc_current_block ()->f2k_derived; - else - { - /* 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 = ns->st_labels; - while (lp) - { - if (lp->value == labelno) - return lp; - - if (lp->value < labelno) - lp = lp->left; - else - lp = lp->right; - } - - lp = XCNEW (gfc_st_label); - - lp->value = labelno; - lp->defined = ST_LABEL_UNKNOWN; - lp->referenced = ST_LABEL_UNKNOWN; - lp->ns = ns; - - gfc_insert_bbt (&ns->st_labels, lp, compare_st_labels); - - return lp; -} - - -/* Called when a statement with a statement label is about to be - accepted. We add the label to the list of the current namespace, - making sure it hasn't been defined previously and referenced - correctly. */ - -void -gfc_define_st_label (gfc_st_label *lp, gfc_sl_type type, locus *label_locus) -{ - int labelno; - - labelno = lp->value; - - if (lp->defined != ST_LABEL_UNKNOWN) - gfc_error ("Duplicate statement label %d at %L and %L", labelno, - &lp->where, label_locus); - else - { - lp->where = *label_locus; - - switch (type) - { - case ST_LABEL_FORMAT: - if (lp->referenced == ST_LABEL_TARGET - || lp->referenced == ST_LABEL_DO_TARGET) - gfc_error ("Label %d at %C already referenced as branch target", - labelno); - else - lp->defined = ST_LABEL_FORMAT; - - break; - - case ST_LABEL_TARGET: - case ST_LABEL_DO_TARGET: - if (lp->referenced == ST_LABEL_FORMAT) - gfc_error ("Label %d at %C already referenced as a format label", - labelno); - else - lp->defined = type; - - if (lp->referenced == ST_LABEL_DO_TARGET && type != ST_LABEL_DO_TARGET - && !gfc_notify_std (GFC_STD_F95_OBS | GFC_STD_F2018_DEL, - "DO termination statement which is not END DO" - " or CONTINUE with label %d at %C", labelno)) - return; - break; - - default: - lp->defined = ST_LABEL_BAD_TARGET; - lp->referenced = ST_LABEL_BAD_TARGET; - } - } -} - - -/* Reference a label. Given a label and its type, see if that - reference is consistent with what is known about that label, - updating the unknown state. Returns false if something goes - wrong. */ - -bool -gfc_reference_st_label (gfc_st_label *lp, gfc_sl_type type) -{ - gfc_sl_type label_type; - int labelno; - bool rc; - - if (lp == NULL) - return true; - - labelno = lp->value; - - if (lp->defined != ST_LABEL_UNKNOWN) - label_type = lp->defined; - else - { - label_type = lp->referenced; - lp->where = gfc_current_locus; - } - - if (label_type == ST_LABEL_FORMAT - && (type == ST_LABEL_TARGET || type == ST_LABEL_DO_TARGET)) - { - gfc_error ("Label %d at %C previously used as a FORMAT label", labelno); - rc = false; - goto done; - } - - if ((label_type == ST_LABEL_TARGET || label_type == ST_LABEL_DO_TARGET - || label_type == ST_LABEL_BAD_TARGET) - && type == ST_LABEL_FORMAT) - { - gfc_error ("Label %d at %C previously used as branch target", labelno); - rc = false; - goto done; - } - - if (lp->referenced == ST_LABEL_DO_TARGET && type == ST_LABEL_DO_TARGET - && !gfc_notify_std (GFC_STD_F95_OBS | GFC_STD_F2018_DEL, - "Shared DO termination label %d at %C", labelno)) - return false; - - if (type == ST_LABEL_DO_TARGET - && !gfc_notify_std (GFC_STD_F2018_OBS, "Labeled DO statement " - "at %L", &gfc_current_locus)) - return false; - - if (lp->referenced != ST_LABEL_DO_TARGET) - lp->referenced = type; - rc = true; - -done: - return rc; -} - - -/************** Symbol table management subroutines ****************/ - -/* Basic details: Fortran 95 requires a potentially unlimited number - of distinct namespaces when compiling a program unit. This case - occurs during a compilation of internal subprograms because all of - the internal subprograms must be read before we can start - generating code for the host. - - Given the tricky nature of the Fortran grammar, we must be able to - undo changes made to a symbol table if the current interpretation - of a statement is found to be incorrect. Whenever a symbol is - looked up, we make a copy of it and link to it. All of these - symbols are kept in a vector so that we can commit or - undo the changes at a later time. - - A symtree may point to a symbol node outside of its namespace. In - this case, that symbol has been used as a host associated variable - at some previous time. */ - -/* Allocate a new namespace structure. Copies the implicit types from - PARENT if PARENT_TYPES is set. */ - -gfc_namespace * -gfc_get_namespace (gfc_namespace *parent, int parent_types) -{ - gfc_namespace *ns; - gfc_typespec *ts; - 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->tb_op[in] = NULL; - } - - /* Initialize default implicit types. */ - for (i = 'a'; i <= 'z'; i++) - { - ns->set_flag[i - 'a'] = 0; - ts = &ns->default_type[i - 'a']; - - if (parent_types && ns->parent != NULL) - { - /* Copy parent settings. */ - *ts = ns->parent->default_type[i - 'a']; - continue; - } - - if (flag_implicit_none != 0) - { - gfc_clear_ts (ts); - continue; - } - - if ('i' <= i && i <= 'n') - { - ts->type = BT_INTEGER; - ts->kind = gfc_default_integer_kind; - } - else - { - ts->type = BT_REAL; - ts->kind = gfc_default_real_kind; - } - } - - ns->refs = 1; - - return ns; -} - - -/* Comparison function for symtree nodes. */ - -static int -compare_symtree (void *_st1, void *_st2) -{ - gfc_symtree *st1, *st2; - - st1 = (gfc_symtree *) _st1; - st2 = (gfc_symtree *) _st2; - - return strcmp (st1->name, st2->name); -} - - -/* Allocate a new symtree node and associate it with the new symbol. */ - -gfc_symtree * -gfc_new_symtree (gfc_symtree **root, const char *name) -{ - gfc_symtree *st; - - st = XCNEW (gfc_symtree); - st->name = gfc_get_string ("%s", name); - - gfc_insert_bbt (root, st, compare_symtree); - return st; -} - - -/* Delete a symbol from the tree. Does not free the symbol itself! */ - -void -gfc_delete_symtree (gfc_symtree **root, const char *name) -{ - gfc_symtree st, *st0; - const char *p; - - /* Submodules are marked as mod.submod. When freeing a submodule - symbol, the symtree only has "submod", so adjust that here. */ - - p = strrchr(name, '.'); - if (p) - p++; - else - p = name; - - st0 = gfc_find_symtree (*root, p); - - st.name = gfc_get_string ("%s", p); - gfc_delete_bbt (root, &st, compare_symtree); - - free (st0); -} - - -/* Given a root symtree node and a name, try to find the symbol within - the namespace. Returns NULL if the symbol is not found. */ - -gfc_symtree * -gfc_find_symtree (gfc_symtree *st, const char *name) -{ - int c; - - while (st != NULL) - { - c = strcmp (name, st->name); - if (c == 0) - return st; - - st = (c < 0) ? st->left : st->right; - } - - return NULL; -} - - -/* Return a symtree node with a name that is guaranteed to be unique - within the namespace and corresponds to an illegal fortran name. */ - -gfc_symtree * -gfc_get_unique_symtree (gfc_namespace *ns) -{ - char name[GFC_MAX_SYMBOL_LEN + 1]; - static int serial = 0; - - sprintf (name, "@%d", serial++); - return gfc_new_symtree (&ns->sym_root, name); -} - - -/* Given a name find a user operator node, creating it if it doesn't - exist. These are much simpler than symbols because they can't be - ambiguous with one another. */ - -gfc_user_op * -gfc_get_uop (const char *name) -{ - gfc_user_op *uop; - gfc_symtree *st; - gfc_namespace *ns = gfc_current_ns; - - if (ns->omp_udr_ns) - ns = ns->parent; - st = gfc_find_symtree (ns->uop_root, name); - if (st != NULL) - return st->n.uop; - - st = gfc_new_symtree (&ns->uop_root, name); - - uop = st->n.uop = XCNEW (gfc_user_op); - uop->name = gfc_get_string ("%s", name); - uop->access = ACCESS_UNKNOWN; - uop->ns = ns; - - return uop; -} - - -/* Given a name find the user operator node. Returns NULL if it does - not exist. */ - -gfc_user_op * -gfc_find_uop (const char *name, gfc_namespace *ns) -{ - gfc_symtree *st; - - if (ns == NULL) - ns = gfc_current_ns; - - st = gfc_find_symtree (ns->uop_root, name); - return (st == NULL) ? NULL : st->n.uop; -} - - -/* Update a symbol's common_block field, and take care of the associated - memory management. */ - -static void -set_symbol_common_block (gfc_symbol *sym, gfc_common_head *common_block) -{ - if (sym->common_block == common_block) - return; - - if (sym->common_block && sym->common_block->name[0] != '\0') - { - sym->common_block->refs--; - if (sym->common_block->refs == 0) - free (sym->common_block); - } - sym->common_block = common_block; -} - - -/* Remove a gfc_symbol structure and everything it points to. */ - -void -gfc_free_symbol (gfc_symbol *&sym) -{ - - if (sym == NULL) - return; - - gfc_free_array_spec (sym->as); - - free_components (sym->components); - - gfc_free_expr (sym->value); - - gfc_free_namelist (sym->namelist); - - if (sym->ns != sym->formal_ns) - gfc_free_namespace (sym->formal_ns); - - if (!sym->attr.generic_copy) - gfc_free_interface (sym->generic); - - gfc_free_formal_arglist (sym->formal); - - gfc_free_namespace (sym->f2k_derived); - - set_symbol_common_block (sym, NULL); - - if (sym->param_list) - gfc_free_actual_arglist (sym->param_list); - - free (sym); - sym = NULL; -} - - -/* Decrease the reference counter and free memory when we reach zero. */ - -void -gfc_release_symbol (gfc_symbol *&sym) -{ - if (sym == NULL) - return; - - if (sym->formal_ns != NULL && sym->refs == 2 && sym->formal_ns != sym->ns - && (!sym->attr.entry || !sym->module)) - { - /* As formal_ns contains a reference to sym, delete formal_ns just - before the deletion of sym. */ - gfc_namespace *ns = sym->formal_ns; - sym->formal_ns = NULL; - gfc_free_namespace (ns); - } - - sym->refs--; - if (sym->refs > 0) - return; - - gcc_assert (sym->refs == 0); - gfc_free_symbol (sym); -} - - -/* Allocate and initialize a new symbol node. */ - -gfc_symbol * -gfc_new_symbol (const char *name, gfc_namespace *ns) -{ - gfc_symbol *p; - - p = XCNEW (gfc_symbol); - - gfc_clear_ts (&p->ts); - gfc_clear_attr (&p->attr); - p->ns = ns; - p->declared_at = gfc_current_locus; - p->name = gfc_get_string ("%s", name); - - return p; -} - - -/* Generate an error if a symbol is ambiguous, and set the error flag - on it. */ - -static void -ambiguous_symbol (const char *name, gfc_symtree *st) -{ - - if (st->n.sym->error) - return; - - if (st->n.sym->module) - gfc_error ("Name %qs at %C is an ambiguous reference to %qs " - "from module %qs", name, st->n.sym->name, st->n.sym->module); - else - gfc_error ("Name %qs at %C is an ambiguous reference to %qs " - "from current program unit", name, st->n.sym->name); - - st->n.sym->error = 1; -} - - -/* 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; - select_type_insert_tmp (st); - return; - } -} - - -/* Look for a symtree in the current procedure -- that is, go up to - parent namespaces but only if inside a BLOCK. Returns NULL if not found. */ - -gfc_symtree* -gfc_find_symtree_in_proc (const char* name, gfc_namespace* ns) -{ - while (ns) - { - gfc_symtree* st = gfc_find_symtree (ns->sym_root, name); - if (st) - return st; - - if (!ns->construct_entities) - break; - ns = ns->parent; - } - - return NULL; -} - - -/* 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. */ - -int -gfc_find_sym_tree (const char *name, gfc_namespace *ns, int parent_flag, - gfc_symtree **result) -{ - gfc_symtree *st; - - if (ns == NULL) - ns = gfc_current_ns; - - do - { - 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. */ - if (st->ambiguous && !st->n.sym->attr.generic) - { - ambiguous_symbol (name, st); - return 1; - } - - return 0; - } - - if (!parent_flag) - break; - - /* Don't escape an interface block. */ - if (ns && !ns->has_import_set - && ns->proc_name && ns->proc_name->attr.if_source == IFSRC_IFBODY) - break; - - ns = ns->parent; - } - while (ns != NULL); - - if (gfc_current_state() == COMP_DERIVED - && gfc_current_block ()->attr.pdt_template) - { - gfc_symbol *der = gfc_current_block (); - for (; der; der = gfc_get_derived_super_type (der)) - { - if (der->f2k_derived && der->f2k_derived->sym_root) - { - st = gfc_find_symtree (der->f2k_derived->sym_root, name); - if (st) - break; - } - } - *result = st; - return 0; - } - - *result = NULL; - - return 0; -} - - -/* Same, but returns the symbol instead. */ - -int -gfc_find_symbol (const char *name, gfc_namespace *ns, int parent_flag, - gfc_symbol **result) -{ - gfc_symtree *st; - int i; - - i = gfc_find_sym_tree (name, ns, parent_flag, &st); - - if (st == NULL) - *result = NULL; - else - *result = st->n.sym; - - return i; -} - - -/* Tells whether there is only one set of changes in the stack. */ - -static bool -single_undo_checkpoint_p (void) -{ - if (latest_undo_chgset == &default_undo_chgset_var) - { - gcc_assert (latest_undo_chgset->previous == NULL); - return true; - } - else - { - gcc_assert (latest_undo_chgset->previous != NULL); - return false; - } -} - -/* Save symbol with the information necessary to back it out. */ - -void -gfc_save_symbol_data (gfc_symbol *sym) -{ - gfc_symbol *s; - unsigned i; - - if (!single_undo_checkpoint_p ()) - { - /* If there is more than one change set, look for the symbol in the - current one. If it is found there, we can reuse it. */ - FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, s) - if (s == sym) - { - gcc_assert (sym->gfc_new || sym->old_symbol != NULL); - return; - } - } - else if (sym->gfc_new || sym->old_symbol != NULL) - return; - - s = XCNEW (gfc_symbol); - *s = *sym; - sym->old_symbol = s; - sym->gfc_new = 0; - - latest_undo_chgset->syms.safe_push (sym); -} - - -/* Given a name, find a symbol, or create it if it does not exist yet - in the current namespace. If the symbol is found we make sure that - it's OK. - - The integer return code indicates - 0 All OK - 1 The symbol name was ambiguous - 2 The name meant to be established was already host associated. - - 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, - bool allow_subroutine) -{ - gfc_symtree *st; - gfc_symbol *p; - - /* This doesn't usually happen during resolution. */ - if (ns == NULL) - ns = gfc_current_ns; - - /* Try to find the symbol in ns. */ - st = gfc_find_symtree (ns->sym_root, name); - - if (st == NULL && ns->omp_udr_ns) - { - ns = ns->parent; - st = gfc_find_symtree (ns->sym_root, name); - } - - if (st == NULL) - { - /* If not there, create a new symbol. */ - p = gfc_new_symbol (name, ns); - - /* Add to the list of tentative symbols. */ - p->old_symbol = NULL; - p->mark = 1; - p->gfc_new = 1; - latest_undo_chgset->syms.safe_push (p); - - st = gfc_new_symtree (&ns->sym_root, name); - st->n.sym = p; - p->refs++; - - } - else - { - /* Make sure the existing symbol is OK. Ambiguous - generic interfaces are permitted, as long as the - specific interfaces are different. */ - if (st->ambiguous && !st->n.sym->attr.generic) - { - ambiguous_symbol (name, st); - return 1; - } - - p = st->n.sym; - if (p->ns != ns && (!p->attr.function || ns->proc_name != p) - && !(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 %qs at %C has already been host associated", - name); - return 2; - } - - p->mark = 1; - - /* Copy in case this symbol is changed. */ - gfc_save_symbol_data (p); - } - - *result = st; - return 0; -} - - -int -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, false); - if (i != 0) - return i; - - if (st) - *result = st->n.sym; - else - *result = NULL; - return i; -} - - -/* Subroutine that searches for a symbol, creating it if it doesn't - exist, but tries to host-associate the symbol if possible. */ - -int -gfc_get_ha_sym_tree (const char *name, gfc_symtree **result) -{ - gfc_symtree *st; - int i; - - i = gfc_find_sym_tree (name, gfc_current_ns, 0, &st); - - if (st != NULL) - { - gfc_save_symbol_data (st->n.sym); - *result = st; - return i; - } - - i = gfc_find_sym_tree (name, gfc_current_ns, 1, &st); - if (i) - return i; - - if (st != NULL) - { - *result = st; - return 0; - } - - return gfc_get_sym_tree (name, gfc_current_ns, result, false); -} - - -int -gfc_get_ha_symbol (const char *name, gfc_symbol **result) -{ - int i; - gfc_symtree *st; - - i = gfc_get_ha_sym_tree (name, &st); - - if (st) - *result = st->n.sym; - else - *result = NULL; - - return i; -} - - -/* Search for the symtree belonging to a gfc_common_head; we cannot use - head->name as the common_root symtree's name might be mangled. */ - -static gfc_symtree * -find_common_symtree (gfc_symtree *st, gfc_common_head *head) -{ - - gfc_symtree *result; - - if (st == NULL) - return NULL; - - if (st->n.common == head) - return st; - - result = find_common_symtree (st->left, head); - if (!result) - result = find_common_symtree (st->right, head); - - return result; -} - - -/* Restore previous state of symbol. Just copy simple stuff. */ - -static void -restore_old_symbol (gfc_symbol *p) -{ - gfc_symbol *old; - - p->mark = 0; - old = p->old_symbol; - - p->ts.type = old->ts.type; - p->ts.kind = old->ts.kind; - - p->attr = old->attr; - - if (p->value != old->value) - { - gcc_checking_assert (old->value == NULL); - gfc_free_expr (p->value); - p->value = NULL; - } - - if (p->as != old->as) - { - if (p->as) - gfc_free_array_spec (p->as); - p->as = old->as; - } - - p->generic = old->generic; - p->component_access = old->component_access; - - if (p->namelist != NULL && old->namelist == NULL) - { - gfc_free_namelist (p->namelist); - p->namelist = NULL; - } - else - { - if (p->namelist_tail != old->namelist_tail) - { - gfc_free_namelist (old->namelist_tail->next); - old->namelist_tail->next = NULL; - } - } - - p->namelist_tail = old->namelist_tail; - - if (p->formal != old->formal) - { - gfc_free_formal_arglist (p->formal); - p->formal = old->formal; - } - - set_symbol_common_block (p, old->common_block); - p->common_head = old->common_head; - - p->old_symbol = old->old_symbol; - free (old); -} - - -/* Frees the internal data of a gfc_undo_change_set structure. Doesn't free - the structure itself. */ - -static void -free_undo_change_set_data (gfc_undo_change_set &cs) -{ - cs.syms.release (); - cs.tbps.release (); -} - - -/* Given a change set pointer, free its target's contents and update it with - the address of the previous change set. Note that only the contents are - freed, not the target itself (the contents' container). It is not a problem - as the latter will be a local variable usually. */ - -static void -pop_undo_change_set (gfc_undo_change_set *&cs) -{ - free_undo_change_set_data (*cs); - cs = cs->previous; -} - - -static void free_old_symbol (gfc_symbol *sym); - - -/* Merges the current change set into the previous one. The changes themselves - are left untouched; only one checkpoint is forgotten. */ - -void -gfc_drop_last_undo_checkpoint (void) -{ - gfc_symbol *s, *t; - unsigned i, j; - - FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, s) - { - /* No need to loop in this case. */ - if (s->old_symbol == NULL) - continue; - - /* Remove the duplicate symbols. */ - FOR_EACH_VEC_ELT (latest_undo_chgset->previous->syms, j, t) - if (t == s) - { - latest_undo_chgset->previous->syms.unordered_remove (j); - - /* S->OLD_SYMBOL is the backup symbol for S as it was at the - last checkpoint. We drop that checkpoint, so S->OLD_SYMBOL - shall contain from now on the backup symbol for S as it was - at the checkpoint before. */ - if (s->old_symbol->gfc_new) - { - gcc_assert (s->old_symbol->old_symbol == NULL); - s->gfc_new = s->old_symbol->gfc_new; - free_old_symbol (s); - } - else - restore_old_symbol (s->old_symbol); - break; - } - } - - latest_undo_chgset->previous->syms.safe_splice (latest_undo_chgset->syms); - latest_undo_chgset->previous->tbps.safe_splice (latest_undo_chgset->tbps); - - pop_undo_change_set (latest_undo_chgset); -} - - -/* Undoes all the changes made to symbols since the previous checkpoint. - This subroutine is made simpler due to the fact that attributes are - never removed once added. */ - -void -gfc_restore_last_undo_checkpoint (void) -{ - gfc_symbol *p; - unsigned i; - - FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p) - { - /* Symbol in a common block was new. Or was old and just put in common */ - if (p->common_block - && (p->gfc_new || !p->old_symbol->common_block)) - { - /* If the symbol was added to any common block, it - needs to be removed to stop the resolver looking - for a (possibly) dead symbol. */ - if (p->common_block->head == p && !p->common_next) - { - gfc_symtree st, *st0; - st0 = find_common_symtree (p->ns->common_root, - p->common_block); - if (st0) - { - st.name = st0->name; - gfc_delete_bbt (&p->ns->common_root, &st, compare_symtree); - free (st0); - } - } - - if (p->common_block->head == p) - p->common_block->head = p->common_next; - else - { - gfc_symbol *cparent, *csym; - - cparent = p->common_block->head; - csym = cparent->common_next; - - while (csym != p) - { - cparent = csym; - csym = csym->common_next; - } - - gcc_assert(cparent->common_next == p); - cparent->common_next = csym->common_next; - } - p->common_next = NULL; - } - if (p->gfc_new) - { - /* 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 (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); - } - else - restore_old_symbol (p); - } - - latest_undo_chgset->syms.truncate (0); - latest_undo_chgset->tbps.truncate (0); - - if (!single_undo_checkpoint_p ()) - pop_undo_change_set (latest_undo_chgset); -} - - -/* Makes sure that there is only one set of changes; in other words we haven't - forgotten to pair a call to gfc_new_checkpoint with a call to either - gfc_drop_last_undo_checkpoint or gfc_restore_last_undo_checkpoint. */ - -static void -enforce_single_undo_checkpoint (void) -{ - gcc_checking_assert (single_undo_checkpoint_p ()); -} - - -/* Undoes all the changes made to symbols in the current statement. */ - -void -gfc_undo_symbols (void) -{ - enforce_single_undo_checkpoint (); - gfc_restore_last_undo_checkpoint (); -} - - -/* Free sym->old_symbol. sym->old_symbol is mostly a shallow copy of sym; the - components of old_symbol that might need deallocation are the "allocatables" - that are restored in gfc_undo_symbols(), with two exceptions: namelist and - namelist_tail. In case these differ between old_symbol and sym, it's just - because sym->namelist has gotten a few more items. */ - -static void -free_old_symbol (gfc_symbol *sym) -{ - - if (sym->old_symbol == NULL) - return; - - if (sym->old_symbol->as != sym->as) - gfc_free_array_spec (sym->old_symbol->as); - - if (sym->old_symbol->value != sym->value) - gfc_free_expr (sym->old_symbol->value); - - if (sym->old_symbol->formal != sym->formal) - gfc_free_formal_arglist (sym->old_symbol->formal); - - free (sym->old_symbol); - sym->old_symbol = NULL; -} - - -/* Makes the changes made in the current statement permanent-- gets - rid of undo information. */ - -void -gfc_commit_symbols (void) -{ - gfc_symbol *p; - gfc_typebound_proc *tbp; - unsigned i; - - enforce_single_undo_checkpoint (); - - FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p) - { - p->mark = 0; - p->gfc_new = 0; - free_old_symbol (p); - } - latest_undo_chgset->syms.truncate (0); - - FOR_EACH_VEC_ELT (latest_undo_chgset->tbps, i, tbp) - tbp->error = 0; - latest_undo_chgset->tbps.truncate (0); -} - - -/* Makes the changes made in one symbol permanent -- gets rid of undo - information. */ - -void -gfc_commit_symbol (gfc_symbol *sym) -{ - gfc_symbol *p; - unsigned i; - - enforce_single_undo_checkpoint (); - - FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p) - if (p == sym) - { - latest_undo_chgset->syms.unordered_remove (i); - break; - } - - sym->mark = 0; - sym->gfc_new = 0; - - free_old_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 u.generic */ - free (t->n.tb); - t->n.tb = NULL; - free (t); -} - - -/* Recursive function that deletes an entire tree and all the common - head structures it points to. */ - -static void -free_common_tree (gfc_symtree * common_tree) -{ - if (common_tree == NULL) - return; - - free_common_tree (common_tree->left); - free_common_tree (common_tree->right); - - free (common_tree); -} - - -/* Recursive function that deletes an entire tree and all the common - head structures it points to. */ - -static void -free_omp_udr_tree (gfc_symtree * omp_udr_tree) -{ - if (omp_udr_tree == NULL) - return; - - free_omp_udr_tree (omp_udr_tree->left); - free_omp_udr_tree (omp_udr_tree->right); - - gfc_free_omp_udr (omp_udr_tree->n.omp_udr); - free (omp_udr_tree); -} - - -/* Recursive function that deletes an entire tree and all the user - operator nodes that it contains. */ - -static void -free_uop_tree (gfc_symtree *uop_tree) -{ - if (uop_tree == NULL) - return; - - free_uop_tree (uop_tree->left); - free_uop_tree (uop_tree->right); - - gfc_free_interface (uop_tree->n.uop->op); - free (uop_tree->n.uop); - free (uop_tree); -} - - -/* Recursive function that deletes an entire tree and all the symbols - that it contains. */ - -static void -free_sym_tree (gfc_symtree *sym_tree) -{ - if (sym_tree == NULL) - return; - - free_sym_tree (sym_tree->left); - free_sym_tree (sym_tree->right); - - gfc_release_symbol (sym_tree->n.sym); - free (sym_tree); -} - - -/* Free the gfc_equiv_info's. */ - -static void -gfc_free_equiv_infos (gfc_equiv_info *s) -{ - if (s == NULL) - return; - gfc_free_equiv_infos (s->next); - free (s); -} - - -/* Free the gfc_equiv_lists. */ - -static void -gfc_free_equiv_lists (gfc_equiv_list *l) -{ - if (l == NULL) - return; - gfc_free_equiv_lists (l->next); - gfc_free_equiv_infos (l->equiv); - free (l); -} - - -/* Free a finalizer procedure list. */ - -void -gfc_free_finalizer (gfc_finalizer* el) -{ - if (el) - { - gfc_release_symbol (el->proc_sym); - free (el); - } -} - -static void -gfc_free_finalizer_list (gfc_finalizer* list) -{ - while (list) - { - gfc_finalizer* current = list; - list = list->next; - gfc_free_finalizer (current); - } -} - - -/* 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 (); - - /* 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; - } - - /* Put into namespace. */ - cl->next = ns->cl_list; - ns->cl_list = cl; - - return cl; -} - - -/* Free the charlen list from cl to end (end is not freed). - Free the whole list if end is NULL. */ - -static void -gfc_free_charlen (gfc_charlen *cl, gfc_charlen *end) -{ - gfc_charlen *cl2; - - for (; cl != end; cl = cl2) - { - gcc_assert (cl); - - cl2 = cl->next; - gfc_free_expr (cl->length); - free (cl); - } -} - - -/* Free entry list structs. */ - -static void -free_entry_list (gfc_entry_list *el) -{ - gfc_entry_list *next; - - if (el == NULL) - return; - - next = el->next; - free (el); - free_entry_list (next); -} - - -/* Free a namespace structure and everything below it. Interface - lists associated with intrinsic operators are not freed. These are - taken care of when a specific name is freed. */ - -void -gfc_free_namespace (gfc_namespace *&ns) -{ - gfc_namespace *p, *q; - int i; - gfc_was_finalized *f; - - if (ns == NULL) - return; - - ns->refs--; - if (ns->refs > 0) - return; - - gcc_assert (ns->refs == 0); - - gfc_free_statements (ns->code); - - free_sym_tree (ns->sym_root); - free_uop_tree (ns->uop_root); - free_common_tree (ns->common_root); - free_omp_udr_tree (ns->omp_udr_root); - free_tb_tree (ns->tb_sym_root); - free_tb_tree (ns->tb_uop_root); - gfc_free_finalizer_list (ns->finalizers); - gfc_free_omp_declare_simd_list (ns->omp_declare_simd); - gfc_free_omp_declare_variant_list (ns->omp_declare_variant); - gfc_free_charlen (ns->cl_list, NULL); - free_st_labels (ns->st_labels); - - free_entry_list (ns->entries); - gfc_free_equiv (ns->equiv); - gfc_free_equiv_lists (ns->equiv_lists); - gfc_free_use_stmts (ns->use_stmts); - - for (i = GFC_INTRINSIC_BEGIN; i != GFC_INTRINSIC_END; i++) - gfc_free_interface (ns->op[i]); - - gfc_free_data (ns->data); - - /* Free all the expr + component combinations that have been - finalized. */ - f = ns->was_finalized; - while (f) - { - gfc_was_finalized* current = f; - f = f->next; - free (current); - } - - p = ns->contained; - free (ns); - ns = NULL; - - /* Recursively free any contained namespaces. */ - while (p != NULL) - { - q = p; - p = p->sibling; - gfc_free_namespace (q); - } -} - - -void -gfc_symbol_init_2 (void) -{ - - gfc_current_ns = gfc_get_namespace (NULL, 0); -} - - -void -gfc_symbol_done_2 (void) -{ - if (gfc_current_ns != NULL) - { - /* free everything from the root. */ - while (gfc_current_ns->parent != NULL) - gfc_current_ns = gfc_current_ns->parent; - gfc_free_namespace (gfc_current_ns); - gfc_current_ns = NULL; - } - gfc_derived_types = NULL; - - enforce_single_undo_checkpoint (); - free_undo_change_set_data (*latest_undo_chgset); -} - - -/* Count how many nodes a symtree has. */ - -static unsigned -count_st_nodes (const gfc_symtree *st) -{ - unsigned nodes; - if (!st) - return 0; - - nodes = count_st_nodes (st->left); - nodes++; - nodes += count_st_nodes (st->right); - - return nodes; -} - - -/* Convert symtree tree into symtree vector. */ - -static unsigned -fill_st_vector (gfc_symtree *st, gfc_symtree **st_vec, unsigned node_cntr) -{ - if (!st) - return node_cntr; - - node_cntr = fill_st_vector (st->left, st_vec, node_cntr); - st_vec[node_cntr++] = st; - node_cntr = fill_st_vector (st->right, st_vec, node_cntr); - - return node_cntr; -} - - -/* Traverse namespace. As the functions might modify the symtree, we store the - symtree as a vector and operate on this vector. Note: We assume that - sym_func or st_func never deletes nodes from the symtree - only adding is - allowed. Additionally, newly added nodes are not traversed. */ - -static void -do_traverse_symtree (gfc_symtree *st, void (*st_func) (gfc_symtree *), - void (*sym_func) (gfc_symbol *)) -{ - gfc_symtree **st_vec; - unsigned nodes, i, node_cntr; - - gcc_assert ((st_func && !sym_func) || (!st_func && sym_func)); - nodes = count_st_nodes (st); - st_vec = XALLOCAVEC (gfc_symtree *, nodes); - node_cntr = 0; - fill_st_vector (st, st_vec, node_cntr); - - if (sym_func) - { - /* Clear marks. */ - for (i = 0; i < nodes; i++) - st_vec[i]->n.sym->mark = 0; - for (i = 0; i < nodes; i++) - if (!st_vec[i]->n.sym->mark) - { - (*sym_func) (st_vec[i]->n.sym); - st_vec[i]->n.sym->mark = 1; - } - } - else - for (i = 0; i < nodes; i++) - (*st_func) (st_vec[i]); -} - - -/* Recursively traverse the symtree nodes. */ - -void -gfc_traverse_symtree (gfc_symtree *st, void (*st_func) (gfc_symtree *)) -{ - do_traverse_symtree (st, st_func, NULL); -} - - -/* Call a given function for all symbols in the namespace. We take - care that each gfc_symbol node is called exactly once. */ - -void -gfc_traverse_ns (gfc_namespace *ns, void (*sym_func) (gfc_symbol *)) -{ - do_traverse_symtree (ns->sym_root, NULL, sym_func); -} - - -/* Return TRUE when name is the name of an intrinsic type. */ - -bool -gfc_is_intrinsic_typename (const char *name) -{ - if (strcmp (name, "integer") == 0 - || strcmp (name, "real") == 0 - || strcmp (name, "character") == 0 - || strcmp (name, "logical") == 0 - || strcmp (name, "complex") == 0 - || strcmp (name, "doubleprecision") == 0 - || strcmp (name, "doublecomplex") == 0) - return true; - else - return false; -} - - -/* Return TRUE if the symbol is an automatic variable. */ - -static bool -gfc_is_var_automatic (gfc_symbol *sym) -{ - /* Pointer and allocatable variables are never automatic. */ - if (sym->attr.pointer || sym->attr.allocatable) - return false; - /* Check for arrays with non-constant size. */ - if (sym->attr.dimension && sym->as - && !gfc_is_compile_time_shape (sym->as)) - return true; - /* Check for non-constant length character variables. */ - if (sym->ts.type == BT_CHARACTER - && sym->ts.u.cl - && !gfc_is_constant_expr (sym->ts.u.cl->length)) - return true; - /* Variables with explicit AUTOMATIC attribute. */ - if (sym->attr.automatic) - return true; - - return false; -} - -/* Given a symbol, mark it as SAVEd if it is allowed. */ - -static void -save_symbol (gfc_symbol *sym) -{ - - if (sym->attr.use_assoc) - return; - - if (sym->attr.in_common - || sym->attr.in_equivalence - || sym->attr.dummy - || sym->attr.result - || sym->attr.flavor != FL_VARIABLE) - return; - /* Automatic objects are not saved. */ - if (gfc_is_var_automatic (sym)) - return; - gfc_add_save (&sym->attr, SAVE_EXPLICIT, sym->name, &sym->declared_at); -} - - -/* Mark those symbols which can be SAVEd as such. */ - -void -gfc_save_all (gfc_namespace *ns) -{ - gfc_traverse_ns (ns, save_symbol); -} - - -/* Make sure that no changes to symbols are pending. */ - -void -gfc_enforce_clean_symbol_state(void) -{ - enforce_single_undo_checkpoint (); - gcc_assert (latest_undo_chgset->syms.is_empty ()); -} - - -/************** Global symbol handling ************/ - - -/* Search a tree for the global symbol. */ - -gfc_gsymbol * -gfc_find_gsymbol (gfc_gsymbol *symbol, const char *name) -{ - int c; - - if (symbol == NULL) - return NULL; - - while (symbol) - { - c = strcmp (name, symbol->name); - if (!c) - return symbol; - - symbol = (c < 0) ? symbol->left : symbol->right; - } - - return NULL; -} - - -/* Case insensitive search a tree for the global symbol. */ - -gfc_gsymbol * -gfc_find_case_gsymbol (gfc_gsymbol *symbol, const char *name) -{ - int c; - - if (symbol == NULL) - return NULL; - - while (symbol) - { - c = strcasecmp (name, symbol->name); - if (!c) - return symbol; - - symbol = (c < 0) ? symbol->left : symbol->right; - } - - return NULL; -} - - -/* Compare two global symbols. Used for managing the BB tree. */ - -static int -gsym_compare (void *_s1, void *_s2) -{ - gfc_gsymbol *s1, *s2; - - s1 = (gfc_gsymbol *) _s1; - s2 = (gfc_gsymbol *) _s2; - return strcmp (s1->name, s2->name); -} - - -/* Get a global symbol, creating it if it doesn't exist. */ - -gfc_gsymbol * -gfc_get_gsymbol (const char *name, bool bind_c) -{ - gfc_gsymbol *s; - - s = gfc_find_gsymbol (gfc_gsym_root, name); - if (s != NULL) - return s; - - s = XCNEW (gfc_gsymbol); - s->type = GSYM_UNKNOWN; - s->name = gfc_get_string ("%s", name); - s->bind_c = bind_c; - - gfc_insert_bbt (&gfc_gsym_root, s, gsym_compare); - - return s; -} - -void -gfc_traverse_gsymbol (gfc_gsymbol *gsym, - void (*do_something) (gfc_gsymbol *, void *), - void *data) -{ - if (gsym->left) - gfc_traverse_gsymbol (gsym->left, do_something, data); - - (*do_something) (gsym, data); - - if (gsym->right) - gfc_traverse_gsymbol (gsym->right, do_something, data); -} - -static gfc_symbol * -get_iso_c_binding_dt (int sym_id) -{ - gfc_symbol *dt_list = gfc_derived_types; - - /* Loop through the derived types in the name list, searching for - the desired symbol from iso_c_binding. Search the parent namespaces - if necessary and requested to (parent_flag). */ - if (dt_list) - { - while (dt_list->dt_next != gfc_derived_types) - { - if (dt_list->from_intmod != INTMOD_NONE - && dt_list->intmod_sym_id == sym_id) - return dt_list; - - dt_list = dt_list->dt_next; - } - } - - return NULL; -} - - -/* Verifies that the given derived type symbol, derived_sym, is interoperable - with C. This is necessary for any derived type that is BIND(C) and for - derived types that are parameters to functions that are BIND(C). All - fields of the derived type are required to be interoperable, and are tested - for such. If an error occurs, the errors are reported here, allowing for - multiple errors to be handled for a single derived type. */ - -bool -verify_bind_c_derived_type (gfc_symbol *derived_sym) -{ - gfc_component *curr_comp = NULL; - bool is_c_interop = false; - bool retval = true; - - if (derived_sym == NULL) - gfc_internal_error ("verify_bind_c_derived_type(): Given symbol is " - "unexpectedly NULL"); - - /* If we've already looked at this derived symbol, do not look at it again - so we don't repeat warnings/errors. */ - if (derived_sym->ts.is_c_interop) - return true; - - /* The derived type must have the BIND attribute to be interoperable - J3/04-007, Section 15.2.3. */ - if (derived_sym->attr.is_bind_c != 1) - { - derived_sym->ts.is_c_interop = 0; - gfc_error_now ("Derived type %qs declared at %L must have the BIND " - "attribute to be C interoperable", derived_sym->name, - &(derived_sym->declared_at)); - retval = false; - } - - curr_comp = derived_sym->components; - - /* Fortran 2003 allows an empty derived type. C99 appears to disallow an - empty struct. Section 15.2 in Fortran 2003 states: "The following - subclauses define the conditions under which a Fortran entity is - interoperable. If a Fortran entity is interoperable, an equivalent - entity may be defined by means of C and the Fortran entity is said - to be interoperable with the C entity. There does not have to be such - an interoperating C entity." - */ - if (curr_comp == NULL) - { - gfc_warning (0, "Derived type %qs with BIND(C) attribute at %L is empty, " - "and may be inaccessible by the C companion processor", - derived_sym->name, &(derived_sym->declared_at)); - derived_sym->ts.is_c_interop = 1; - derived_sym->attr.is_bind_c = 1; - return true; - } - - - /* Initialize the derived type as being C interoperable. - If we find an error in the components, this will be set false. */ - derived_sym->ts.is_c_interop = 1; - - /* Loop through the list of components to verify that the kind of - each is a C interoperable type. */ - do - { - /* The components cannot be pointers (fortran sense). - J3/04-007, Section 15.2.3, C1505. */ - if (curr_comp->attr.pointer != 0) - { - gfc_error ("Component %qs at %L cannot have the " - "POINTER attribute because it is a member " - "of the BIND(C) derived type %qs at %L", - curr_comp->name, &(curr_comp->loc), - derived_sym->name, &(derived_sym->declared_at)); - retval = false; - } - - if (curr_comp->attr.proc_pointer != 0) - { - gfc_error ("Procedure pointer component %qs at %L cannot be a member" - " of the BIND(C) derived type %qs at %L", curr_comp->name, - &curr_comp->loc, derived_sym->name, - &derived_sym->declared_at); - retval = false; - } - - /* The components cannot be allocatable. - J3/04-007, Section 15.2.3, C1505. */ - if (curr_comp->attr.allocatable != 0) - { - gfc_error ("Component %qs at %L cannot have the " - "ALLOCATABLE attribute because it is a member " - "of the BIND(C) derived type %qs at %L", - curr_comp->name, &(curr_comp->loc), - derived_sym->name, &(derived_sym->declared_at)); - retval = false; - } - - /* BIND(C) derived types must have interoperable components. */ - if (curr_comp->ts.type == BT_DERIVED - && 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 cannot - 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.u.derived); - } - else - { - /* Grab the typespec for the given component and test the kind. */ - is_c_interop = gfc_verify_c_interop (&(curr_comp->ts)); - - if (!is_c_interop) - { - /* Report warning and continue since not fatal. The - draft does specify a constraint that requires all fields - to interoperate, but if the user says real(4), etc., it - may interoperate with *something* in C, but the compiler - most likely won't know exactly what. Further, it may not - interoperate with the same data type(s) in C if the user - recompiles with different flags (e.g., -m32 and -m64 on - x86_64 and using integer(4) to claim interop with a - C_LONG). */ - if (derived_sym->attr.is_bind_c == 1 && warn_c_binding_type) - /* If the derived type is bind(c), all fields must be - interop. */ - gfc_warning (OPT_Wc_binding_type, - "Component %qs in derived type %qs at %L " - "may not be C interoperable, even though " - "derived type %qs is BIND(C)", - curr_comp->name, derived_sym->name, - &(curr_comp->loc), derived_sym->name); - else if (warn_c_binding_type) - /* If derived type is param to bind(c) routine, or to one - of the iso_c_binding procs, it must be interoperable, so - all fields must interop too. */ - gfc_warning (OPT_Wc_binding_type, - "Component %qs in derived type %qs at %L " - "may not be C interoperable", - curr_comp->name, derived_sym->name, - &(curr_comp->loc)); - } - } - - curr_comp = curr_comp->next; - } while (curr_comp != NULL); - - if (derived_sym->attr.sequence != 0) - { - gfc_error ("Derived type %qs at %L cannot have the SEQUENCE " - "attribute because it is BIND(C)", derived_sym->name, - &(derived_sym->declared_at)); - retval = false; - } - - /* Mark the derived type as not being C interoperable if we found an - error. If there were only warnings, proceed with the assumption - it's interoperable. */ - if (!retval) - derived_sym->ts.is_c_interop = 0; - - return retval; -} - - -/* Generate symbols for the named constants c_null_ptr and c_null_funptr. */ - -static bool -gen_special_c_interop_ptr (gfc_symbol *tmp_sym, gfc_symtree *dt_symtree) -{ - gfc_constructor *c; - - gcc_assert (tmp_sym && dt_symtree && dt_symtree->n.sym); - dt_symtree->n.sym->attr.referenced = 1; - - tmp_sym->attr.is_c_interop = 1; - tmp_sym->attr.is_bind_c = 1; - tmp_sym->ts.is_c_interop = 1; - tmp_sym->ts.is_iso_c = 1; - tmp_sym->ts.type = BT_DERIVED; - tmp_sym->ts.f90_type = BT_VOID; - tmp_sym->attr.flavor = FL_PARAMETER; - tmp_sym->ts.u.derived = dt_symtree->n.sym; - - /* Set the c_address field of c_null_ptr and c_null_funptr to - the value of NULL. */ - tmp_sym->value = gfc_get_expr (); - tmp_sym->value->expr_type = EXPR_STRUCTURE; - tmp_sym->value->ts.type = BT_DERIVED; - tmp_sym->value->ts.f90_type = BT_VOID; - tmp_sym->value->ts.u.derived = tmp_sym->ts.u.derived; - gfc_constructor_append_expr (&tmp_sym->value->value.constructor, NULL, NULL); - c = gfc_constructor_first (tmp_sym->value->value.constructor); - c->expr = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0); - c->expr->ts.is_iso_c = 1; - - return true; -} - - -/* Add a formal argument, gfc_formal_arglist, to the - end of the given list of arguments. Set the reference to the - provided symbol, param_sym, in the argument. */ - -static void -add_formal_arg (gfc_formal_arglist **head, - gfc_formal_arglist **tail, - gfc_formal_arglist *formal_arg, - gfc_symbol *param_sym) -{ - /* Put in list, either as first arg or at the tail (curr arg). */ - if (*head == NULL) - *head = *tail = formal_arg; - else - { - (*tail)->next = formal_arg; - (*tail) = formal_arg; - } - - (*tail)->sym = param_sym; - (*tail)->next = NULL; - - return; -} - - -/* Add a procedure interface to the given symbol (i.e., store a - reference to the list of formal arguments). */ - -static void -add_proc_interface (gfc_symbol *sym, ifsrc source, gfc_formal_arglist *formal) -{ - - sym->formal = formal; - 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 - used when creating procedure declaration variables from a procedure - declaration statement (see match_proc_decl()) to create the formal - args based on the args of a given named interface. - - When an actual argument list is provided, skip the absent arguments - unless copy_type is true. - To be used together with gfc_se->ignore_optional. */ - -void -gfc_copy_formal_args_intr (gfc_symbol *dest, gfc_intrinsic_sym *src, - gfc_actual_arglist *actual, bool copy_type) -{ - 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; - gfc_actual_arglist *act_arg = actual; - /* 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) - { - /* Skip absent arguments. */ - if (actual) - { - gcc_assert (act_arg != NULL); - if (act_arg->expr == NULL) - { - act_arg = act_arg->next; - continue; - } - } - 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. */ - if (copy_type && act_arg->expr != NULL) - { - formal_arg->sym->ts = act_arg->expr->ts; - if (act_arg->expr->rank > 0) - { - formal_arg->sym->attr.dimension = 1; - formal_arg->sym->as = gfc_get_array_spec(); - formal_arg->sym->as->rank = -1; - formal_arg->sym->as->type = AS_ASSUMED_RANK; - } - if (act_arg->name && strcmp (act_arg->name, "%VAL") == 0) - formal_arg->sym->pass_as_value = 1; - } - else - formal_arg->sym->ts = curr_arg->ts; - - formal_arg->sym->attr.optional = curr_arg->optional; - formal_arg->sym->attr.value = curr_arg->value; - 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); - - /* Validate changes. */ - gfc_commit_symbol (formal_arg->sym); - if (actual) - act_arg = act_arg->next; - } - - /* 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; -} - - -static int -std_for_isocbinding_symbol (int id) -{ - switch (id) - { -#define NAMED_INTCST(a,b,c,d) \ - case a:\ - return d; -#include "iso-c-binding.def" -#undef NAMED_INTCST - -#define NAMED_FUNCTION(a,b,c,d) \ - case a:\ - return d; -#define NAMED_SUBROUTINE(a,b,c,d) \ - case a:\ - return d; -#include "iso-c-binding.def" -#undef NAMED_FUNCTION -#undef NAMED_SUBROUTINE - - default: - return GFC_STD_F2003; - } -} - -/* Generate the given set of C interoperable kind objects, or all - interoperable kinds. This function will only be given kind objects - for valid iso_c_binding defined types because this is verified when - the 'use' statement is parsed. If the user gives an 'only' clause, - the specific kinds are looked up; if they don't exist, an error is - reported. If the user does not give an 'only' clause, all - iso_c_binding symbols are generated. If a list of specific kinds - is given, it must have a NULL in the first empty spot to mark the - end of the list. For C_null_(fun)ptr, dt_symtree has to be set and - point to the symtree for c_(fun)ptr. */ - -gfc_symtree * -generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s, - const char *local_name, gfc_symtree *dt_symtree, - bool hidden) -{ - const char *const name = (local_name && local_name[0]) - ? local_name : c_interop_kinds_table[s].name; - gfc_symtree *tmp_symtree; - gfc_symbol *tmp_sym = NULL; - int index; - - if (gfc_notification_std (std_for_isocbinding_symbol (s)) == ERROR) - return NULL; - - tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name); - if (hidden - && (!tmp_symtree || !tmp_symtree->n.sym - || tmp_symtree->n.sym->from_intmod != INTMOD_ISO_C_BINDING - || tmp_symtree->n.sym->intmod_sym_id != s)) - tmp_symtree = NULL; - - /* Already exists in this scope so don't re-add it. */ - if (tmp_symtree != NULL && (tmp_sym = tmp_symtree->n.sym) != NULL - && (!tmp_sym->attr.generic - || (tmp_sym = gfc_find_dt_in_generic (tmp_sym)) != NULL) - && tmp_sym->from_intmod == INTMOD_ISO_C_BINDING) - { - if (tmp_sym->attr.flavor == FL_DERIVED - && !get_iso_c_binding_dt (tmp_sym->intmod_sym_id)) - { - if (gfc_derived_types) - { - tmp_sym->dt_next = gfc_derived_types->dt_next; - gfc_derived_types->dt_next = tmp_sym; - } - else - { - tmp_sym->dt_next = tmp_sym; - } - gfc_derived_types = tmp_sym; - } - - return tmp_symtree; - } - - /* Create the sym tree in the current ns. */ - if (hidden) - { - tmp_symtree = gfc_get_unique_symtree (gfc_current_ns); - tmp_sym = gfc_new_symbol (name, gfc_current_ns); - - /* Add to the list of tentative symbols. */ - latest_undo_chgset->syms.safe_push (tmp_sym); - tmp_sym->old_symbol = NULL; - tmp_sym->mark = 1; - tmp_sym->gfc_new = 1; - - tmp_symtree->n.sym = tmp_sym; - tmp_sym->refs++; - } - else - { - gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false); - gcc_assert (tmp_symtree); - tmp_sym = tmp_symtree->n.sym; - } - - /* Say what module this symbol belongs to. */ - tmp_sym->module = gfc_get_string ("%s", mod_name); - tmp_sym->from_intmod = INTMOD_ISO_C_BINDING; - tmp_sym->intmod_sym_id = s; - tmp_sym->attr.is_iso_c = 1; - tmp_sym->attr.use_assoc = 1; - - gcc_assert (dt_symtree == NULL || s == ISOCBINDING_NULL_FUNPTR - || s == ISOCBINDING_NULL_PTR); - - switch (s) - { - -#define NAMED_INTCST(a,b,c,d) case a : -#define NAMED_REALCST(a,b,c,d) case a : -#define NAMED_CMPXCST(a,b,c,d) case a : -#define NAMED_LOGCST(a,b,c) case a : -#define NAMED_CHARKNDCST(a,b,c) case a : -#include "iso-c-binding.def" - - tmp_sym->value = gfc_get_int_expr (gfc_default_integer_kind, NULL, - c_interop_kinds_table[s].value); - - /* Initialize an integer constant expression node. */ - tmp_sym->attr.flavor = FL_PARAMETER; - tmp_sym->ts.type = BT_INTEGER; - tmp_sym->ts.kind = gfc_default_integer_kind; - - /* Mark this type as a C interoperable one. */ - tmp_sym->ts.is_c_interop = 1; - tmp_sym->ts.is_iso_c = 1; - tmp_sym->value->ts.is_c_interop = 1; - tmp_sym->value->ts.is_iso_c = 1; - tmp_sym->attr.is_c_interop = 1; - - /* Tell what f90 type this c interop kind is valid. */ - tmp_sym->ts.f90_type = c_interop_kinds_table[s].f90_type; - - break; - - -#define NAMED_CHARCST(a,b,c) case a : -#include "iso-c-binding.def" - - /* Initialize an integer constant expression node for the - length of the character. */ - tmp_sym->value = gfc_get_character_expr (gfc_default_character_kind, - &gfc_current_locus, NULL, 1); - tmp_sym->value->ts.is_c_interop = 1; - tmp_sym->value->ts.is_iso_c = 1; - tmp_sym->value->value.character.length = 1; - tmp_sym->value->value.character.string[0] - = (gfc_char_t) c_interop_kinds_table[s].value; - tmp_sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); - tmp_sym->ts.u.cl->length = gfc_get_int_expr (gfc_charlen_int_kind, - NULL, 1); - - /* May not need this in both attr and ts, but do need in - attr for writing module file. */ - tmp_sym->attr.is_c_interop = 1; - - tmp_sym->attr.flavor = FL_PARAMETER; - tmp_sym->ts.type = BT_CHARACTER; - - /* Need to set it to the C_CHAR kind. */ - tmp_sym->ts.kind = gfc_default_character_kind; - - /* Mark this type as a C interoperable one. */ - tmp_sym->ts.is_c_interop = 1; - tmp_sym->ts.is_iso_c = 1; - - /* Tell what f90 type this c interop kind is valid. */ - tmp_sym->ts.f90_type = BT_CHARACTER; - - break; - - case ISOCBINDING_PTR: - case ISOCBINDING_FUNPTR: - { - gfc_symbol *dt_sym; - gfc_component *tmp_comp = NULL; - - /* Generate real derived type. */ - if (hidden) - dt_sym = tmp_sym; - else - { - const char *hidden_name; - gfc_interface *intr, *head; - - 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); - gfc_get_sym_tree (hidden_name, gfc_current_ns, &tmp_symtree, false); - dt_sym = tmp_symtree->n.sym; - dt_sym->name = gfc_get_string (s == ISOCBINDING_PTR - ? "c_ptr" : "c_funptr"); - - /* Generate an artificial generic function. */ - head = tmp_sym->generic; - intr = gfc_get_interface (); - intr->sym = dt_sym; - intr->where = gfc_current_locus; - intr->next = head; - tmp_sym->generic = intr; - - if (!tmp_sym->attr.generic - && !gfc_add_generic (&tmp_sym->attr, tmp_sym->name, NULL)) - return NULL; - - if (!tmp_sym->attr.function - && !gfc_add_function (&tmp_sym->attr, tmp_sym->name, NULL)) - return NULL; - } - - /* Say what module this symbol belongs to. */ - dt_sym->module = gfc_get_string ("%s", mod_name); - dt_sym->from_intmod = INTMOD_ISO_C_BINDING; - dt_sym->intmod_sym_id = s; - dt_sym->attr.use_assoc = 1; - - /* Initialize an integer constant expression node. */ - dt_sym->attr.flavor = FL_DERIVED; - dt_sym->ts.is_c_interop = 1; - dt_sym->attr.is_c_interop = 1; - dt_sym->attr.private_comp = 1; - dt_sym->component_access = ACCESS_PRIVATE; - dt_sym->ts.is_iso_c = 1; - dt_sym->ts.type = BT_DERIVED; - dt_sym->ts.f90_type = BT_VOID; - - /* A derived type must have the bind attribute to be - interoperable (J3/04-007, Section 15.2.3), even though - the binding label is not used. */ - dt_sym->attr.is_bind_c = 1; - - dt_sym->attr.referenced = 1; - dt_sym->ts.u.derived = dt_sym; - - /* Add the symbol created for the derived type to the current ns. */ - if (gfc_derived_types) - { - dt_sym->dt_next = gfc_derived_types->dt_next; - gfc_derived_types->dt_next = dt_sym; - } - else - { - dt_sym->dt_next = dt_sym; - } - gfc_derived_types = dt_sym; - - gfc_add_component (dt_sym, "c_address", &tmp_comp); - if (tmp_comp == NULL) - gcc_unreachable (); - - tmp_comp->ts.type = BT_INTEGER; - - /* Set this because the module will need to read/write this field. */ - tmp_comp->ts.f90_type = BT_INTEGER; - - /* The kinds for c_ptr and c_funptr are the same. */ - index = get_c_kind ("c_ptr", c_interop_kinds_table); - tmp_comp->ts.kind = c_interop_kinds_table[index].value; - tmp_comp->attr.access = ACCESS_PRIVATE; - - /* Mark the component as C interoperable. */ - tmp_comp->ts.is_c_interop = 1; - } - - break; - - case ISOCBINDING_NULL_PTR: - case ISOCBINDING_NULL_FUNPTR: - gen_special_c_interop_ptr (tmp_sym, dt_symtree); - break; - - default: - gcc_unreachable (); - } - gfc_commit_symbol (tmp_sym); - return tmp_symtree; -} - - -/* Check that a symbol is already typed. If strict is not set, an untyped - symbol is acceptable for non-standard-conforming mode. */ - -bool -gfc_check_symbol_typed (gfc_symbol* sym, gfc_namespace* ns, - bool strict, locus where) -{ - gcc_assert (sym); - - if (gfc_matching_prefix) - return true; - - /* Check for the type and try to give it an implicit one. */ - if (sym->ts.type == BT_UNKNOWN - && !gfc_set_default_type (sym, 0, ns)) - { - if (strict) - { - gfc_error ("Symbol %qs is used before it is typed at %L", - sym->name, &where); - return false; - } - - if (!gfc_notify_std (GFC_STD_GNU, "Symbol %qs is used before" - " it is typed at %L", sym->name, &where)) - return false; - } - - /* Everything is ok. */ - return true; -} - - -/* 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 (gfc_typebound_proc *tb0) -{ - gfc_typebound_proc *result; - - result = XCNEW (gfc_typebound_proc); - if (tb0) - *result = *tb0; - result->error = 1; - - latest_undo_chgset->tbps.safe_push (result); - - return result; -} - - -/* Get the super-type of a given derived type. */ - -gfc_symbol* -gfc_get_derived_super_type (gfc_symbol* derived) -{ - gcc_assert (derived); - - if (derived->attr.generic) - derived = gfc_find_dt_in_generic (derived); - - if (!derived->attr.extension) - return NULL; - - gcc_assert (derived->components); - gcc_assert (derived->components->ts.type == BT_DERIVED); - gcc_assert (derived->components->ts.u.derived); - - if (derived->components->ts.u.derived->attr.generic) - return gfc_find_dt_in_generic (derived->components->ts.u.derived); - - return derived->components->ts.u.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); -} - - -/* 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) -{ - 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); - bool is_union1 = (ts1->type == BT_UNION); - bool is_union2 = (ts2->type == BT_UNION); - - if (is_class1 - && ts1->u.derived->components - && ((ts1->u.derived->attr.is_class - && ts1->u.derived->components->ts.u.derived->attr - .unlimited_polymorphic) - || ts1->u.derived->attr.unlimited_polymorphic)) - return 1; - - if (!is_derived1 && !is_derived2 && !is_class1 && !is_class2 - && !is_union1 && !is_union2) - return (ts1->type == ts2->type); - - if ((is_derived1 && is_derived2) || (is_union1 && is_union2)) - return gfc_compare_derived_types (ts1->u.derived, ts2->u.derived); - - if (is_derived1 && is_class2) - return gfc_compare_derived_types (ts1->u.derived, - ts2->u.derived->attr.is_class ? - ts2->u.derived->components->ts.u.derived - : ts2->u.derived); - if (is_class1 && is_derived2) - return gfc_type_is_extension_of (ts1->u.derived->attr.is_class ? - ts1->u.derived->components->ts.u.derived - : ts1->u.derived, - ts2->u.derived); - else if (is_class1 && is_class2) - return gfc_type_is_extension_of (ts1->u.derived->attr.is_class ? - ts1->u.derived->components->ts.u.derived - : ts1->u.derived, - ts2->u.derived->attr.is_class ? - ts2->u.derived->components->ts.u.derived - : ts2->u.derived); - else - return 0; -} - - -/* Find the parent-namespace of the current function. If we're inside - BLOCK constructs, it may not be the current one. */ - -gfc_namespace* -gfc_find_proc_namespace (gfc_namespace* ns) -{ - while (ns->construct_entities) - { - ns = ns->parent; - gcc_assert (ns); - } - - return ns; -} - - -/* Check if an associate-variable should be translated as an `implicit' pointer - internally (if it is associated to a variable and not an array with - descriptor). */ - -bool -gfc_is_associate_pointer (gfc_symbol* sym) -{ - if (!sym->assoc) - return false; - - if (sym->ts.type == BT_CLASS) - return true; - - if (sym->ts.type == BT_CHARACTER - && sym->ts.deferred - && sym->assoc->target - && sym->assoc->target->expr_type == EXPR_FUNCTION) - return true; - - if (!sym->assoc->variable) - return false; - - if (sym->attr.dimension && sym->as->type != AS_EXPLICIT) - return false; - - return true; -} - - -gfc_symbol * -gfc_find_dt_in_generic (gfc_symbol *sym) -{ - gfc_interface *intr = NULL; - - if (!sym || gfc_fl_struct (sym->attr.flavor)) - return sym; - - if (sym->attr.generic) - for (intr = sym->generic; intr; intr = intr->next) - if (gfc_fl_struct (intr->sym->attr.flavor)) - break; - return intr ? intr->sym : NULL; -} - - -/* Get the dummy arguments from a procedure symbol. If it has been declared - via a PROCEDURE statement with a named interface, ts.interface will be set - and the arguments need to be taken from there. */ - -gfc_formal_arglist * -gfc_sym_get_dummy_args (gfc_symbol *sym) -{ - gfc_formal_arglist *dummies; - - if (sym == NULL) - return NULL; - - dummies = sym->formal; - if (dummies == NULL && sym->ts.interface != NULL) - dummies = sym->ts.interface->formal; - - return dummies; -} |