summaryrefslogtreecommitdiff
path: root/gcc/fortran/primary.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/primary.c')
-rw-r--r--gcc/fortran/primary.c311
1 files changed, 272 insertions, 39 deletions
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index c2faa0f3e1..c12dc3562d 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1,5 +1,5 @@
/* Primary expression subroutines
- Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2000-2017 Free Software Foundation, Inc.
Contributed by Andy Vaught
This file is part of GCC.
@@ -41,7 +41,6 @@ match_kind_param (int *kind, int *is_iso_c)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym;
- const char *p;
match m;
*is_iso_c = 0;
@@ -68,8 +67,7 @@ match_kind_param (int *kind, int *is_iso_c)
if (sym->value == NULL)
return MATCH_NO;
- p = gfc_extract_int (sym->value, kind);
- if (p != NULL)
+ if (gfc_extract_int (sym->value, kind))
return MATCH_NO;
gfc_set_sym_referenced (sym);
@@ -257,7 +255,6 @@ match_hollerith_constant (gfc_expr **result)
{
locus old_loc;
gfc_expr *e = NULL;
- const char *msg;
int num, pad;
int i;
@@ -270,12 +267,8 @@ match_hollerith_constant (gfc_expr **result)
if (!gfc_notify_std (GFC_STD_LEGACY, "Hollerith constant at %C"))
goto cleanup;
- msg = gfc_extract_int (e, &num);
- if (msg != NULL)
- {
- gfc_error (msg);
- goto cleanup;
- }
+ if (gfc_extract_int (e, &num, 1))
+ goto cleanup;
if (num == 0)
{
gfc_error ("Invalid Hollerith constant: %L must contain at least "
@@ -483,7 +476,7 @@ backup:
static match
match_real_constant (gfc_expr **result, int signflag)
{
- int kind, count, seen_dp, seen_digits, is_iso_c;
+ int kind, count, seen_dp, seen_digits, is_iso_c, default_exponent;
locus old_loc, temp_loc;
char *p, *buffer, c, exp_char;
gfc_expr *e;
@@ -494,6 +487,7 @@ match_real_constant (gfc_expr **result, int signflag)
e = NULL;
+ default_exponent = 0;
count = 0;
seen_dp = 0;
seen_digits = 0;
@@ -575,8 +569,14 @@ match_real_constant (gfc_expr **result, int signflag)
if (!ISDIGIT (c))
{
- gfc_error ("Missing exponent in real number at %C");
- return MATCH_ERROR;
+ /* With -fdec, default exponent to 0 instead of complaining. */
+ if (flag_dec)
+ default_exponent = 1;
+ else
+ {
+ gfc_error ("Missing exponent in real number at %C");
+ return MATCH_ERROR;
+ }
}
while (ISDIGIT (c))
@@ -597,8 +597,8 @@ done:
gfc_current_locus = old_loc;
gfc_gobble_whitespace ();
- buffer = (char *) alloca (count + 1);
- memset (buffer, '\0', count + 1);
+ buffer = (char *) alloca (count + default_exponent + 1);
+ memset (buffer, '\0', count + default_exponent + 1);
p = buffer;
c = gfc_next_ascii_char ();
@@ -621,6 +621,8 @@ done:
c = gfc_next_ascii_char ();
}
+ if (default_exponent)
+ *p++ = '0';
kind = get_kind (&is_iso_c);
if (kind == -1)
@@ -1008,7 +1010,6 @@ match_string_constant (gfc_expr **result)
locus old_locus, start_locus;
gfc_symbol *sym;
gfc_expr *e;
- const char *q;
match m;
gfc_char_t c, delimiter, *p;
@@ -1073,12 +1074,8 @@ match_string_constant (gfc_expr **result)
if (kind == -1)
{
- q = gfc_extract_int (sym->value, &kind);
- if (q != NULL)
- {
- gfc_error (q);
- return MATCH_ERROR;
- }
+ if (gfc_extract_int (sym->value, &kind, 1))
+ return MATCH_ERROR;
gfc_set_sym_referenced (sym);
}
@@ -1353,6 +1350,10 @@ match_complex_constant (gfc_expr **result)
if (gfc_match_char (',') == MATCH_NO)
{
+ /* It is possible that gfc_int2real issued a warning when
+ converting an integer to real. Throw this away here. */
+
+ gfc_clear_warning ();
gfc_pop_error (&old_error);
m = MATCH_NO;
goto cleanup;
@@ -1554,7 +1555,7 @@ match_actual_arg (gfc_expr **result)
gfc_set_sym_referenced (sym);
if (sym->attr.flavor == FL_NAMELIST)
{
- gfc_error ("Namelist '%s' can not be an argument at %L",
+ gfc_error ("Namelist %qs can not be an argument at %L",
sym->name, &where);
break;
}
@@ -1646,7 +1647,7 @@ match_keyword_arg (gfc_actual_arglist *actual, gfc_actual_arglist *base)
}
}
- actual->name = gfc_get_string (name);
+ actual->name = gfc_get_string ("%s", name);
return MATCH_YES;
cleanup:
@@ -1686,18 +1687,21 @@ match_arg_list_function (gfc_actual_arglist *result)
result->name = "%LOC";
break;
}
+ /* FALLTHRU */
case 'r':
if (strncmp (name, "ref", 3) == 0)
{
result->name = "%REF";
break;
}
+ /* FALLTHRU */
case 'v':
if (strncmp (name, "val", 3) == 0)
{
result->name = "%VAL";
break;
}
+ /* FALLTHRU */
default:
m = MATCH_ERROR;
goto cleanup;
@@ -1915,15 +1919,36 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
}
/* For associate names, we may not yet know whether they are arrays or not.
- Thus if we have one and parentheses follow, we have to assume that it
- actually is one for now. The final decision will be made at
- resolution time, of course. */
- if (sym->assoc && gfc_peek_ascii_char () == '('
- && !(sym->assoc->dangling && sym->assoc->st
+ If the selector expression is unambiguously an array; eg. a full array
+ or an array section, then the associate name must be an array and we can
+ fix it now. Otherwise, if parentheses follow and it is not a character
+ type, we have to assume that it actually is one for now. The final
+ decision will be made at resolution, of course. */
+ if (sym->assoc
+ && gfc_peek_ascii_char () == '('
+ && sym->ts.type != BT_CLASS
+ && !sym->attr.dimension)
+ {
+ if ((!sym->assoc->dangling
+ && sym->assoc->target
+ && sym->assoc->target->ref
+ && sym->assoc->target->ref->type == REF_ARRAY
+ && (sym->assoc->target->ref->u.ar.type == AR_FULL
+ || sym->assoc->target->ref->u.ar.type == AR_SECTION))
+ ||
+ (!(sym->assoc->dangling || sym->ts.type == BT_CHARACTER)
+ && sym->assoc->st
&& sym->assoc->st->n.sym
- && sym->assoc->st->n.sym->attr.dimension == 0)
- && sym->ts.type != BT_CLASS)
+ && sym->assoc->st->n.sym->attr.dimension == 0))
+ {
sym->attr.dimension = 1;
+ if (sym->as == NULL && sym->assoc
+ && sym->assoc->st
+ && sym->assoc->st->n.sym
+ && sym->assoc->st->n.sym->as)
+ sym->as = gfc_copy_array_spec (sym->assoc->st->n.sym->as);
+ }
+ }
if ((equiv_flag && gfc_peek_ascii_char () == '(')
|| gfc_peek_ascii_char () == '[' || sym->attr.codimension
@@ -2013,7 +2038,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
if (m != MATCH_YES)
return MATCH_ERROR;
- if (sym->f2k_derived)
+ if (sym && sym->f2k_derived)
tbp = gfc_find_typebound_proc (sym, &t, name, false, &gfc_current_locus);
else
tbp = NULL;
@@ -2185,7 +2210,15 @@ check_substring:
}
}
- /* F2008, C727. */
+ /* F08:C611. */
+ if (primary->ts.type == BT_DERIVED && primary->ref
+ && primary->ts.u.derived && primary->ts.u.derived->attr.abstract)
+ {
+ gfc_error ("Nonpolymorphic reference to abstract type at %C");
+ return MATCH_ERROR;
+ }
+
+ /* F08:C727. */
if (primary->expr_type == EXPR_PPC && gfc_is_coindexed (primary))
{
gfc_error ("Coindexed procedure-pointer component at %C");
@@ -2356,6 +2389,10 @@ gfc_expr_attr (gfc_expr *e)
attr.allocatable = CLASS_DATA (sym)->attr.allocatable;
}
}
+ else if (e->value.function.isym
+ && e->value.function.isym->transformational
+ && e->ts.type == BT_CLASS)
+ attr = CLASS_DATA (e)->attr;
else
attr = gfc_variable_attr (e, NULL);
@@ -2373,6 +2410,181 @@ gfc_expr_attr (gfc_expr *e)
}
+/* Given an expression, figure out what the ultimate expression
+ attribute is. This routine is similar to gfc_variable_attr with
+ parts of gfc_expr_attr, but focuses more on the needs of
+ coarrays. For coarrays a codimension attribute is kind of
+ "infectious" being propagated once set and never cleared.
+ The coarray_comp is only set, when the expression refs a coarray
+ component. REFS_COMP is set when present to true only, when this EXPR
+ refs a (non-_data) component. To check whether EXPR refs an allocatable
+ component in a derived type coarray *refs_comp needs to be set and
+ coarray_comp has to false. */
+
+static symbol_attribute
+caf_variable_attr (gfc_expr *expr, bool in_allocate, bool *refs_comp)
+{
+ int dimension, codimension, pointer, allocatable, target, coarray_comp;
+ symbol_attribute attr;
+ gfc_ref *ref;
+ gfc_symbol *sym;
+ gfc_component *comp;
+
+ if (expr->expr_type != EXPR_VARIABLE && expr->expr_type != EXPR_FUNCTION)
+ gfc_internal_error ("gfc_caf_attr(): Expression isn't a variable");
+
+ sym = expr->symtree->n.sym;
+ gfc_clear_attr (&attr);
+
+ if (refs_comp)
+ *refs_comp = false;
+
+ if (sym->ts.type == BT_CLASS && sym->attr.class_ok)
+ {
+ dimension = CLASS_DATA (sym)->attr.dimension;
+ codimension = CLASS_DATA (sym)->attr.codimension;
+ pointer = CLASS_DATA (sym)->attr.class_pointer;
+ allocatable = CLASS_DATA (sym)->attr.allocatable;
+ attr.alloc_comp = CLASS_DATA (sym)->ts.u.derived->attr.alloc_comp;
+ attr.pointer_comp = CLASS_DATA (sym)->ts.u.derived->attr.pointer_comp;
+ }
+ else
+ {
+ dimension = sym->attr.dimension;
+ codimension = sym->attr.codimension;
+ pointer = sym->attr.pointer;
+ allocatable = sym->attr.allocatable;
+ attr.alloc_comp = sym->ts.type == BT_DERIVED
+ ? sym->ts.u.derived->attr.alloc_comp : 0;
+ attr.pointer_comp = sym->ts.type == BT_DERIVED
+ ? sym->ts.u.derived->attr.pointer_comp : 0;
+ }
+
+ target = coarray_comp = 0;
+ if (pointer || attr.proc_pointer)
+ target = 1;
+
+ for (ref = expr->ref; ref; ref = ref->next)
+ switch (ref->type)
+ {
+ case REF_ARRAY:
+
+ switch (ref->u.ar.type)
+ {
+ case AR_FULL:
+ case AR_SECTION:
+ dimension = 1;
+ break;
+
+ case AR_ELEMENT:
+ /* Handle coarrays. */
+ if (ref->u.ar.dimen > 0 && !in_allocate)
+ allocatable = pointer = 0;
+ break;
+
+ case AR_UNKNOWN:
+ /* If any of start, end or stride is not integer, there will
+ already have been an error issued. */
+ int errors;
+ gfc_get_errors (NULL, &errors);
+ if (errors == 0)
+ gfc_internal_error ("gfc_caf_attr(): Bad array reference");
+ }
+
+ break;
+
+ case REF_COMPONENT:
+ comp = ref->u.c.component;
+
+ if (comp->ts.type == BT_CLASS)
+ {
+ /* Set coarray_comp only, when this component introduces the
+ coarray. */
+ coarray_comp = !codimension && CLASS_DATA (comp)->attr.codimension;
+ codimension |= CLASS_DATA (comp)->attr.codimension;
+ pointer = CLASS_DATA (comp)->attr.class_pointer;
+ allocatable = CLASS_DATA (comp)->attr.allocatable;
+ }
+ else
+ {
+ /* Set coarray_comp only, when this component introduces the
+ coarray. */
+ coarray_comp = !codimension && comp->attr.codimension;
+ codimension |= comp->attr.codimension;
+ pointer = comp->attr.pointer;
+ allocatable = comp->attr.allocatable;
+ }
+
+ if (refs_comp && strcmp (comp->name, "_data") != 0
+ && (ref->next == NULL
+ || (ref->next->type == REF_ARRAY && ref->next->next == NULL)))
+ *refs_comp = true;
+
+ if (pointer || attr.proc_pointer)
+ target = 1;
+
+ break;
+
+ case REF_SUBSTRING:
+ allocatable = pointer = 0;
+ break;
+ }
+
+ attr.dimension = dimension;
+ attr.codimension = codimension;
+ attr.pointer = pointer;
+ attr.allocatable = allocatable;
+ attr.target = target;
+ attr.save = sym->attr.save;
+ attr.coarray_comp = coarray_comp;
+
+ return attr;
+}
+
+
+symbol_attribute
+gfc_caf_attr (gfc_expr *e, bool in_allocate, bool *refs_comp)
+{
+ symbol_attribute attr;
+
+ switch (e->expr_type)
+ {
+ case EXPR_VARIABLE:
+ attr = caf_variable_attr (e, in_allocate, refs_comp);
+ break;
+
+ case EXPR_FUNCTION:
+ gfc_clear_attr (&attr);
+
+ if (e->value.function.esym && e->value.function.esym->result)
+ {
+ gfc_symbol *sym = e->value.function.esym->result;
+ attr = sym->attr;
+ if (sym->ts.type == BT_CLASS)
+ {
+ attr.dimension = CLASS_DATA (sym)->attr.dimension;
+ attr.pointer = CLASS_DATA (sym)->attr.class_pointer;
+ attr.allocatable = CLASS_DATA (sym)->attr.allocatable;
+ attr.alloc_comp = CLASS_DATA (sym)->ts.u.derived->attr.alloc_comp;
+ attr.pointer_comp = CLASS_DATA (sym)->ts.u.derived
+ ->attr.pointer_comp;
+ }
+ }
+ else if (e->symtree)
+ attr = caf_variable_attr (e, in_allocate, refs_comp);
+ else
+ gfc_clear_attr (&attr);
+ break;
+
+ default:
+ gfc_clear_attr (&attr);
+ break;
+ }
+
+ return attr;
+}
+
+
/* Match a structure constructor. The initial symbol has already been
seen. */
@@ -2458,7 +2670,7 @@ build_actual_constructor (gfc_structure_ctor_component **comp_head,
&& CLASS_DATA (comp)->attr.allocatable))
{
if (!gfc_notify_std (GFC_STD_F2008, "No initializer for "
- "allocatable component '%qs' given in the "
+ "allocatable component %qs given in the "
"structure constructor at %C", comp->name))
return false;
}
@@ -2807,9 +3019,20 @@ gfc_match_rvalue (gfc_expr **result)
bool implicit_char;
gfc_ref *ref;
- m = gfc_match_name (name);
- if (m != MATCH_YES)
- return m;
+ m = gfc_match ("%%loc");
+ if (m == MATCH_YES)
+ {
+ if (!gfc_notify_std (GFC_STD_LEGACY, "%%LOC() as an rvalue at %C"))
+ return MATCH_ERROR;
+ strncpy (name, "loc", 4);
+ }
+
+ else
+ {
+ m = gfc_match_name (name);
+ if (m != MATCH_YES)
+ return m;
+ }
/* Check if the symbol exists. */
if (gfc_find_sym_tree (name, NULL, 1, &symtree))
@@ -3076,6 +3299,15 @@ gfc_match_rvalue (gfc_expr **result)
if (sym->result == NULL)
sym->result = sym;
+ gfc_gobble_whitespace ();
+ /* F08:C612. */
+ if (gfc_peek_ascii_char() == '%')
+ {
+ gfc_error ("The leftmost part-ref in a data-ref can not be a "
+ "function reference at %C");
+ m = MATCH_ERROR;
+ }
+
m = MATCH_YES;
break;
@@ -3339,7 +3571,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
&& (dt_sym = gfc_find_dt_in_generic (sym)))
{
if (dt_sym->attr.flavor == FL_DERIVED)
- gfc_error ("Derived type '%s' cannot be used as a variable at %C",
+ gfc_error ("Derived type %qs cannot be used as a variable at %C",
sym->name);
return MATCH_ERROR;
}
@@ -3412,6 +3644,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
break;
/* Fall through to error */
+ gcc_fallthrough ();
default:
gfc_error ("%qs at %C is not a variable", sym->name);