Dear Mikael, dear all,
Please find attached a revised version of the patch that, I believe,
addresses all the comments. The patch is very much improved and these
improvements are verified by the two extra testcases. Thanks a
million!
Most of the effort involved in preparing this revised patch was
associated with getting rid of ICEs/segfaults triggered by error
recovery. The error handling in resolve_ptr_fcn_assign is still a bit
clumsy but its behaviour is more consistent.
Bootstraps and regtests on FC21/x86_64 - OK for trunk?
Cheers
Paul
2015-09-25 Paul Thomas <[email protected]>
* decl.c (get_proc_name): Return if statement function is
found.
* expr.c (gfc_check_vardef_context): Add error return for
derived type expression lacking the derived type itself.
* io.c (next_char_not_space): Change tab warning to warning now
to prevent locus being lost.
* match.c (gfc_match_ptr_fcn_assign): New function.
* match.h : Add prototype for gfc_match_ptr_fcn_assign.
* parse.c : Add static flag 'in_specification_block'.
(decode_statement): If in specification block match a statement
function, then, if standard embraces F2008 and no error arising
from statement function matching, try to match pointer function
assignment.
(parse_interface): Set 'in_specification_block' on exiting from
parse_spec.
(parse_spec): Set and then reset 'in_specification_block'.
(gfc_parse_file): Set 'in_specification_block'.
* resolve.c (get_temp_from_expr): Extend to include functions
and array constructors as rvalues..
(resolve_ptr_fcn_assign): New function.
(gfc_resolve_code): Call it on finding a pointer function as an
lvalue. If valid or on error, go back to start of resolve_code.
* symbol.c (gfc_add_procedure): Add a sentence to the error to
flag up the ambiguity between a statement function and pointer
function assignment at the end of the specification block.
2015-09-25 Paul Thomas <[email protected]>
* gfortran.dg/fmt_tab_1.f90: Change from run to compile and set
standard as legacy.
* gfortran.dg/function_types_3.f90: Change error message to
"Type inaccessible...."
* gfortran.dg/ptr_func_assign_1.f08: New test.
* gfortran.dg/ptr_func_assign_2.f08: New test.
2015-09-25 Mikael Morin <[email protected]>
* gfortran.dg/ptr_func_assign_3.f08: New test.
* gfortran.dg/ptr_func_assign_4.f08: New test.
On 18 September 2015 at 10:36, Paul Richard Thomas
<[email protected]> wrote:
> Dear Mikael,
>
> Thank you very much for the review. I'll give consideration to your
> remarks over the weekend. You will have guessed from the comment that
> I too was uneasy about forcing the break. As for your last remark,
> yes, the code rewriting is indeed in the wrong place. It should be
> rather easy to accomplish both the checks and defined assignments.
>
> Thanks again
>
> Paul
>
> On 17 September 2015 at 15:43, Mikael Morin <[email protected]> wrote:
>> Le 06/09/2015 18:40, Paul Richard Thomas a écrit :
>>>
>>> It helps to attach the patch :-)
>>>
>>> Paul
>>>
>>> On 6 September 2015 at 13:42, Paul Richard Thomas
>>> <[email protected]> wrote:
>>>>
>>>> Dear All,
>>>>
>>>> The attached patch more or less implements the assignment of
>>>> expressions to the result of a pointer function. To wit:
>>>>
>>>> my_ptr_fcn (arg1, arg2...) = expr
>>>>
>>>> arg1 would usually be the target, pointed to by the function. The
>>>> patch parses these statements and resolves them into:
>>>>
>>>> temp_ptr => my_ptr_fcn (arg1, arg2...)
>>>> temp_ptr = expr
>>>>
>>>> I say more or less implemented because I have ducked one of the
>>>> headaches here. At the end of the specification block, there is an
>>>> ambiguity between statement functions and pointer function
>>>> assignments. I do not even try to resolve this ambiguity and require
>>>> that there be at least one other type of executable statement before
>>>> these beasts. This can undoubtedly be fixed but the effort seems to me
>>>> to be unwarranted at the present time.
>>>>
>>>> This version of the patch extends the coverage of allowed rvalues to
>>>> any legal expression. Also, all the problems with error.c have been
>>>> dealt with by Manuel's patch.
>>>>
>>>> I am grateful to Dominique for reminding me of PR40054 and pointing
>>>> out PR63921. After a remark of his on #gfortran, I fixed the checking
>>>> of the standard to pick up all the offending lines with F2003 and
>>>> earlier.
>>>>
>>>>
>>>> Bootstraps and regtests on FC21/x86_64 - OK for trunk?
>>>>
>> Hello Paul,
>>
>> I'm mostly concerned about the position where the code rewriting happens.
>> Details below.
>>
>> Mikael
>>
>>
>>>
>>> submit_2.diff
>>>
>>
>>> Index: gcc/fortran/parse.c
>>> ===================================================================
>>> *** gcc/fortran/parse.c (revision 227508)
>>> --- gcc/fortran/parse.c (working copy)
>>> *************** decode_statement (void)
>>> *** 356,362 ****
>>> --- 357,371 ----
>>>
>>> match (NULL, gfc_match_assignment, ST_ASSIGNMENT);
>>> match (NULL, gfc_match_pointer_assignment, ST_POINTER_ASSIGNMENT);
>>> +
>>> + if (in_specification_block)
>>> + {
>>> match (NULL, gfc_match_st_function, ST_STATEMENT_FUNCTION);
>>> + }
>>> + else if (!gfc_notification_std (GFC_STD_F2008))
>>> + {
>>> + match (NULL, gfc_match_ptr_fcn_assign, ST_ASSIGNMENT);
>>> + }
>>>
>> As match exits the function upon success, I think it makes sense to move
>> match (... gfc_match_ptr_fcn_assign ...) out of the else, namely:
>>
>> if (in_specification_block)
>> {
>> /* match statement function */
>> }
>>
>> /* match pointer fonction assignment */
>>
>> so that non-ambiguous cases are recognized with gfc_match_ptr_fcn_assign.
>> Non-ambiguous cases are for example the ones where one of the function
>> arguments is a non-variable, or a variable with a subreference, or when
>> there is one keyword argument. Example (rejected with unclassifiable
>> statement):
>>
>> program p
>> integer, parameter :: b = 3
>> integer, target :: a = 2
>>
>> func(arg=b) = 1
>> if (a /= 1) call abort
>>
>> func(b + b - 3) = -1
>> if (a /= -1) call abort
>>
>> contains
>> function func(arg) result(r)
>> integer, pointer :: r
>> integer :: arg
>>
>> if (arg == 3) then
>> r => a
>> else
>> r => null()
>> end if
>> end function func
>> end program p
>>
>>
>>> Index: gcc/fortran/resolve.c
>>> ===================================================================
>>> *** gcc/fortran/resolve.c (revision 227508)
>>> --- gcc/fortran/resolve.c (working copy)
>>> *************** generate_component_assignments (gfc_code
>>> *** 10133,10138 ****
>>> --- 10141,10205 ----
>>> }
>>>
>>>
>>> + /* F2008: Pointer function assignments are of the form:
>>> + ptr_fcn (args) = expr
>>> + This function breaks these assignments into two statements:
>>> + temporary_pointer => ptr_fcn(args)
>>> + temporary_pointer = expr */
>>> +
>>> + static bool
>>> + resolve_ptr_fcn_assign (gfc_code **code, gfc_namespace *ns)
>>> + {
>>> + gfc_expr *tmp_ptr_expr;
>>> + gfc_code *this_code;
>>> + gfc_component *comp;
>>> + gfc_symbol *s;
>>> +
>>> + if ((*code)->expr1->expr_type != EXPR_FUNCTION)
>>> + return false;
>>> +
>>> + /* Even if standard does not support this feature, continue to build
>>> + the two statements to avoid upsetting frontend_passes.c. */
>>
>> I don't mind this, but maybe we should return false at the end, when an
>> error has been emitted?
>>
>>> + gfc_notify_std (GFC_STD_F2008, "Pointer procedure assignment at "
>>> + "%L", &(*code)->loc);
>>> +
>>> + comp = gfc_get_proc_ptr_comp ((*code)->expr1);
>>> +
>>> + if (comp)
>>> + s = comp->ts.interface;
>>> + else
>>> + s = (*code)->expr1->symtree->n.sym;
>>> +
>>> + if (s == NULL || !s->result->attr.pointer)
>>> + {
>>> + gfc_error ("F2008: The function result at %L must have "
>>> + "the pointer attribute.", &(*code)->expr1->where);
>>> + /* Return true because we want a break after the call. */
>>
>> Hum, I would rather not do this if possible. Do we really need the break?
>>
>>> + return true;
>>> + }
>>> +
>>> + tmp_ptr_expr = get_temp_from_expr ((*code)->expr2, ns);
>>> +
>>> + /* get_temp_from_expression is set up for ordinary assignments. To
>>> that
>>> + end, where array bounds are not known, arrays are made allocatable.
>>> + Change the temporary to a pointer here. */
>>> + tmp_ptr_expr->symtree->n.sym->attr.pointer = 1;
>>> + tmp_ptr_expr->symtree->n.sym->attr.allocatable = 0;
>>> +
>>> + this_code = build_assignment (EXEC_ASSIGN,
>>> + tmp_ptr_expr, (*code)->expr2,
>>> + NULL, NULL, (*code)->loc);
>>> + this_code->next = (*code)->next;
>>> + (*code)->next = this_code;
>>> + (*code)->op = EXEC_POINTER_ASSIGN;
>>> + (*code)->expr2 = (*code)->expr1;
>>> + (*code)->expr1 = tmp_ptr_expr;
>>> +
>>> + *code = (*code)->next;
>>> + return true;
>>> + }
>>> +
>>> +
>>> /* Given a block of code, recursively resolve everything pointed to by
>>> this
>>> code block. */
>>>
>>> *************** gfc_resolve_code (gfc_code *code, gfc_na
>>> *** 10318,10323 ****
>>> --- 10385,10393 ----
>>> && code->expr1->value.function.isym->id == GFC_ISYM_CAF_GET)
>>> remove_caf_get_intrinsic (code->expr1);
>>>
>>> + if (resolve_ptr_fcn_assign (&code, ns))
>>> + break;
>>> +
>>> if (!gfc_check_vardef_context (code->expr1, false, false, false,
>>> _("assignment")))
>>> break;
>>
>>
>> I think the call should be added later in the pipeline, and I suspect the
>> break should be removed.
>> As it stands, the code bypasses many of the checks we do normally for
>> assignments.
>> For example, the following is accepted, despite the incompatible ranks.
>>
>> program p
>> integer, target :: a(3) = 2
>> integer :: b(3, 3) = 1
>> integer :: c
>>
>> c = 1
>> ! func(b(2, 2)) = b
>> func(c) = b
>>
>> contains
>> function func(arg) result(r)
>> integer, pointer :: r(:)
>> integer :: arg
>>
>> if (arg == 1) then
>> r => a
>> else
>> r => null()
>> end if
>> end function func
>> end program p
>>
>>
>> I'm also concerned about defined assignments.
>> Combining them with pointer function lhs should be possible, The code
>> rewriting just has to happen at the right place. ;-)
>
>
>
> --
> Outside of a dog, a book is a man's best friend. Inside of a dog it's
> too dark to read.
>
> Groucho Marx
--
Outside of a dog, a book is a man's best friend. Inside of a dog it's
too dark to read.
Groucho Marx
Index: gcc/fortran/decl.c
===================================================================
*** gcc/fortran/decl.c (revision 227854)
--- gcc/fortran/decl.c (working copy)
*************** get_proc_name (const char *name, gfc_sym
*** 901,906 ****
--- 901,908 ----
return rc;
sym = *result;
+ if (sym->attr.proc == PROC_ST_FUNCTION)
+ return rc;
if (sym->attr.module_procedure
&& sym->attr.if_source == IFSRC_IFBODY)
Index: gcc/fortran/expr.c
===================================================================
*** gcc/fortran/expr.c (revision 227854)
--- gcc/fortran/expr.c (working copy)
*************** gfc_check_vardef_context (gfc_expr* e, b
*** 4822,4827 ****
--- 4822,4836 ----
return false;
}
+ if (e->ts.type == BT_DERIVED
+ && e->ts.u.derived == NULL)
+ {
+ if (context)
+ gfc_error ("Type inaccessible in variable definition context (%s) "
+ "at %L", context, &e->where);
+ return false;
+ }
+
/* F2008, C1303. */
if (!alloc_obj
&& (attr.lock_comp
Index: gcc/fortran/match.c
===================================================================
*** gcc/fortran/match.c (revision 227854)
--- gcc/fortran/match.c (working copy)
*************** match
*** 4886,4892 ****
gfc_match_st_function (void)
{
gfc_error_buffer old_error;
-
gfc_symbol *sym;
gfc_expr *expr;
match m;
--- 4886,4891 ----
*************** gfc_match_st_function (void)
*** 4926,4931 ****
--- 4925,4990 ----
return MATCH_YES;
undo_error:
+ gfc_pop_error (&old_error);
+ return MATCH_NO;
+ }
+
+
+ /* Match an assignment to a pointer function (F2008). This could, in
+ general be ambiguous with a statement function. In this implementation
+ it remains so if it is the first statement after the specification
+ block. */
+
+ match
+ gfc_match_ptr_fcn_assign (void)
+ {
+ gfc_error_buffer old_error;
+ locus old_loc;
+ gfc_symbol *sym;
+ gfc_expr *expr;
+ match m;
+ char name[GFC_MAX_SYMBOL_LEN + 1];
+
+ old_loc = gfc_current_locus;
+ m = gfc_match_name (name);
+ if (m != MATCH_YES)
+ return m;
+
+ gfc_find_symbol (name, NULL, 1, &sym);
+ if (sym && sym->attr.flavor != FL_PROCEDURE)
+ return MATCH_NO;
+
+ gfc_push_error (&old_error);
+
+ if (sym && sym->attr.function)
+ goto match_actual_arglist;
+
+ gfc_current_locus = old_loc;
+ m = gfc_match_symbol (&sym, 0);
+ if (m != MATCH_YES)
+ return m;
+
+ if (!gfc_add_procedure (&sym->attr, PROC_UNKNOWN, sym->name, NULL))
+ goto undo_error;
+
+ match_actual_arglist:
+ gfc_current_locus = old_loc;
+ m = gfc_match (" %e", &expr);
+ if (m != MATCH_YES)
+ goto undo_error;
+
+ new_st.op = EXEC_ASSIGN;
+ new_st.expr1 = expr;
+ expr = NULL;
+
+ m = gfc_match (" = %e%t", &expr);
+ if (m != MATCH_YES)
+ goto undo_error;
+
+ new_st.expr2 = expr;
+ return MATCH_YES;
+
+ undo_error:
gfc_pop_error (&old_error);
return MATCH_NO;
}
Index: gcc/fortran/match.h
===================================================================
*** gcc/fortran/match.h (revision 227854)
--- gcc/fortran/match.h (working copy)
*************** match gfc_match_namelist (void);
*** 107,112 ****
--- 107,113 ----
match gfc_match_module (void);
match gfc_match_equivalence (void);
match gfc_match_st_function (void);
+ match gfc_match_ptr_fcn_assign (void);
match gfc_match_case (void);
match gfc_match_select (void);
match gfc_match_select_type (void);
Index: gcc/fortran/parse.c
===================================================================
*** gcc/fortran/parse.c (revision 227854)
--- gcc/fortran/parse.c (working copy)
*************** end_of_block:
*** 287,292 ****
--- 287,293 ----
return ST_GET_FCN_CHARACTERISTICS;
}
+ static bool in_specification_block;
/* This is the primary 'decode_statement'. */
static gfc_statement
*************** decode_statement (void)
*** 356,362 ****
match (NULL, gfc_match_assignment, ST_ASSIGNMENT);
match (NULL, gfc_match_pointer_assignment, ST_POINTER_ASSIGNMENT);
! match (NULL, gfc_match_st_function, ST_STATEMENT_FUNCTION);
match (NULL, gfc_match_data_decl, ST_DATA_DECL);
match (NULL, gfc_match_enumerator_def, ST_ENUMERATOR);
--- 357,375 ----
match (NULL, gfc_match_assignment, ST_ASSIGNMENT);
match (NULL, gfc_match_pointer_assignment, ST_POINTER_ASSIGNMENT);
!
! if (in_specification_block)
! {
! m = match_word (NULL, gfc_match_st_function, &old_locus);
! if (m == MATCH_YES)
! return ST_STATEMENT_FUNCTION;
! }
!
! if (!(in_specification_block && m == MATCH_ERROR)
! && !gfc_notification_std (GFC_STD_F2008))
! {
! match (NULL, gfc_match_ptr_fcn_assign, ST_ASSIGNMENT);
! }
match (NULL, gfc_match_data_decl, ST_DATA_DECL);
match (NULL, gfc_match_enumerator_def, ST_ENUMERATOR);
*************** loop:
*** 3008,3013 ****
--- 3021,3027 ----
decl:
/* Read data declaration statements. */
st = parse_spec (ST_NONE);
+ in_specification_block = true;
/* Since the interface block does not permit an IMPLICIT statement,
the default type for the function or the result must be taken
*************** parse_spec (gfc_statement st)
*** 3136,3141 ****
--- 3150,3157 ----
bool bad_characteristic = false;
gfc_typespec *ts;
+ in_specification_block = true;
+
verify_st_order (&ss, ST_NONE, false);
if (st == ST_NONE)
st = next_statement ();
*************** declSt:
*** 3369,3374 ****
--- 3385,3392 ----
ts->type = BT_UNKNOWN;
}
+ in_specification_block = false;
+
return st;
}
*************** gfc_parse_file (void)
*** 5589,5594 ****
--- 5607,5613 ----
if (gfc_at_eof ())
goto done;
+ in_specification_block = true;
loop:
gfc_init_2 ();
st = next_statement ();
Index: gcc/fortran/resolve.c
===================================================================
*** gcc/fortran/resolve.c (revision 227854)
--- gcc/fortran/resolve.c (working copy)
*************** get_temp_from_expr (gfc_expr *e, gfc_nam
*** 9735,9746 ****
ref = NULL;
aref = NULL;
- /* This function could be expanded to support other expression type
- but this is not needed here. */
- gcc_assert (e->expr_type == EXPR_VARIABLE);
-
/* Obtain the arrayspec for the temporary. */
! if (e->rank)
{
aref = gfc_find_array_ref (e);
if (e->expr_type == EXPR_VARIABLE
--- 9735,9744 ----
ref = NULL;
aref = NULL;
/* Obtain the arrayspec for the temporary. */
! if (e->rank && e->expr_type != EXPR_ARRAY
! && e->expr_type != EXPR_FUNCTION
! && e->expr_type != EXPR_OP)
{
aref = gfc_find_array_ref (e);
if (e->expr_type == EXPR_VARIABLE
*************** get_temp_from_expr (gfc_expr *e, gfc_nam
*** 9772,9777 ****
--- 9770,9785 ----
if (as->type == AS_DEFERRED)
tmp->n.sym->attr.allocatable = 1;
}
+ else if (e->rank && (e->expr_type == EXPR_ARRAY
+ || e->expr_type == EXPR_FUNCTION
+ || e->expr_type == EXPR_OP))
+ {
+ tmp->n.sym->as = gfc_get_array_spec ();
+ tmp->n.sym->as->type = AS_DEFERRED;
+ tmp->n.sym->as->rank = e->rank;
+ tmp->n.sym->attr.allocatable = 1;
+ tmp->n.sym->attr.dimension = 1;
+ }
else
tmp->n.sym->attr.dimension = 0;
*************** generate_component_assignments (gfc_code
*** 10133,10138 ****
--- 10141,10205 ----
}
+ /* F2008: Pointer function assignments are of the form:
+ ptr_fcn (args) = expr
+ This function breaks these assignments into two statements:
+ temporary_pointer => ptr_fcn(args)
+ temporary_pointer = expr */
+
+ static bool
+ resolve_ptr_fcn_assign (gfc_code **code, gfc_namespace *ns)
+ {
+ gfc_expr *tmp_ptr_expr;
+ gfc_code *this_code;
+ gfc_component *comp;
+ gfc_symbol *s;
+
+ if ((*code)->expr1->expr_type != EXPR_FUNCTION)
+ return false;
+
+ /* Even if standard does not support this feature, continue to build
+ the two statements to avoid upsetting frontend_passes.c. */
+ gfc_notify_std (GFC_STD_F2008, "Pointer procedure assignment at "
+ "%L", &(*code)->loc);
+
+ comp = gfc_get_proc_ptr_comp ((*code)->expr1);
+
+ if (comp)
+ s = comp->ts.interface;
+ else
+ s = (*code)->expr1->symtree->n.sym;
+
+ if (s == NULL || !s->result->attr.pointer)
+ {
+ gfc_error ("F2008: The function result at %L must have "
+ "the pointer attribute.", &(*code)->expr1->where);
+ (*code)->op = EXEC_NOP;
+ return false;
+ }
+
+ tmp_ptr_expr = get_temp_from_expr ((*code)->expr2, ns);
+
+ /* get_temp_from_expression is set up for ordinary assignments. To that
+ end, where array bounds are not known, arrays are made allocatable.
+ Change the temporary to a pointer here. */
+ tmp_ptr_expr->symtree->n.sym->attr.pointer = 1;
+ tmp_ptr_expr->symtree->n.sym->attr.allocatable = 0;
+ tmp_ptr_expr->where = (*code)->loc;
+
+ this_code = build_assignment (EXEC_ASSIGN,
+ tmp_ptr_expr, (*code)->expr2,
+ NULL, NULL, (*code)->loc);
+ this_code->next = (*code)->next;
+ (*code)->next = this_code;
+ (*code)->op = EXEC_POINTER_ASSIGN;
+ (*code)->expr2 = (*code)->expr1;
+ (*code)->expr1 = tmp_ptr_expr;
+
+ return true;
+ }
+
+
/* Given a block of code, recursively resolve everything pointed to by this
code block. */
*************** gfc_resolve_code (gfc_code *code, gfc_na
*** 10228,10234 ****
if (omp_workshare_save != -1)
omp_workshare_flag = omp_workshare_save;
}
!
t = true;
if (code->op != EXEC_COMPCALL && code->op != EXEC_CALL_PPC)
t = gfc_resolve_expr (code->expr1);
--- 10295,10301 ----
if (omp_workshare_save != -1)
omp_workshare_flag = omp_workshare_save;
}
! start:
t = true;
if (code->op != EXEC_COMPCALL && code->op != EXEC_CALL_PPC)
t = gfc_resolve_expr (code->expr1);
*************** gfc_resolve_code (gfc_code *code, gfc_na
*** 10318,10323 ****
--- 10385,10398 ----
&& code->expr1->value.function.isym->id == GFC_ISYM_CAF_GET)
remove_caf_get_intrinsic (code->expr1);
+ /* If this is a pointer function in an lvalue variable context,
+ the new code will have to be resolved afresh. This is also the
+ case with an error, where the code is transformed into NOP to
+ prevent ICEs downstream. */
+ if (resolve_ptr_fcn_assign (&code, ns)
+ || code->op == EXEC_NOP)
+ goto start;
+
if (!gfc_check_vardef_context (code->expr1, false, false, false,
_("assignment")))
break;
*************** gfc_resolve_code (gfc_code *code, gfc_na
*** 10332,10337 ****
--- 10407,10413 ----
/* F03 7.4.1.3 for non-allocatable, non-pointer components. */
if (code->op != EXEC_CALL && code->expr1->ts.type == BT_DERIVED
+ && code->expr1->ts.u.derived
&& code->expr1->ts.u.derived->attr.defined_assign_comp)
generate_component_assignments (&code, ns);
Index: gcc/fortran/symbol.c
===================================================================
*** gcc/fortran/symbol.c (revision 227854)
--- gcc/fortran/symbol.c (working copy)
*************** gfc_add_procedure (symbol_attribute *att
*** 1541,1549 ****
if (attr->proc != PROC_UNKNOWN && !attr->module_procedure)
{
! gfc_error ("%s procedure at %L is already declared as %s procedure",
gfc_code2string (procedures, t), where,
gfc_code2string (procedures, attr->proc));
return false;
}
--- 1541,1559 ----
if (attr->proc != PROC_UNKNOWN && !attr->module_procedure)
{
! 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;
}
Index: gcc/testsuite/gfortran.dg/fmt_tab_1.f90
===================================================================
*** gcc/testsuite/gfortran.dg/fmt_tab_1.f90 (revision 227854)
--- gcc/testsuite/gfortran.dg/fmt_tab_1.f90 (working copy)
***************
*** 1,4 ****
! ! { dg-do run }
! PR fortran/32987
program TestFormat
write (*, 10)
--- 1,5 ----
! ! { dg-do compile }
! ! { dg-options -Wno-error=tabs }
! PR fortran/32987
program TestFormat
write (*, 10)
Index: gcc/testsuite/gfortran.dg/function_types_3.f90
===================================================================
*** gcc/testsuite/gfortran.dg/function_types_3.f90 (revision 227854)
--- gcc/testsuite/gfortran.dg/function_types_3.f90 (working copy)
*************** end
*** 15,19 ****
! PR 50403: SIGSEGV in gfc_use_derived
type(f) function f() ! { dg-error "Type name 'f' at .1. conflicts with
previously declared entity|The type for function 'f' at .1. is not accessible" }
! f=110 ! { dg-error "Unclassifiable statement" }
end
--- 15,19 ----
! PR 50403: SIGSEGV in gfc_use_derived
type(f) function f() ! { dg-error "Type name 'f' at .1. conflicts with
previously declared entity|The type for function 'f' at .1. is not accessible" }
! f=110 ! { dg-error "Type inaccessible in variable definition
context" }
end
Index: gcc/testsuite/gfortran.dg/ptr_func_assign_1.f08
===================================================================
*** gcc/testsuite/gfortran.dg/ptr_func_assign_1.f08 (revision 0)
--- gcc/testsuite/gfortran.dg/ptr_func_assign_1.f08 (working copy)
***************
*** 0 ****
--- 1,112 ----
+ ! { dg-do run }
+ !
+ ! Tests implementation of F2008 feature: pointer function assignments.
+ !
+ ! Contributed by Paul Thomas <[email protected]>
+ !
+ module fcn_bar
+ contains
+ function bar (arg, idx) result (res)
+ integer, pointer :: res
+ integer, target :: arg(:)
+ integer :: idx
+ res => arg (idx)
+ res = 99
+ end function
+ end module
+
+ module fcn_mydt
+ type mydt
+ integer, allocatable, dimension (:) :: i
+ contains
+ procedure, pass :: create
+ procedure, pass :: delete
+ procedure, pass :: fill
+ procedure, pass :: elem_fill
+ end type
+ contains
+ subroutine create (this, sz)
+ class(mydt) :: this
+ integer :: sz
+ if (allocated (this%i)) deallocate (this%i)
+ allocate (this%i(sz))
+ this%i = 0
+ end subroutine
+ subroutine delete (this)
+ class(mydt) :: this
+ if (allocated (this%i)) deallocate (this%i)
+ end subroutine
+ function fill (this, idx) result (res)
+ integer, pointer :: res(:)
+ integer :: lb, ub
+ class(mydt), target :: this
+ integer :: idx
+ lb = idx
+ ub = lb + size(this%i) - 1
+ res => this%i(lb:ub)
+ end function
+ function elem_fill (this, idx) result (res)
+ integer, pointer :: res
+ class(mydt), target :: this
+ integer :: idx
+ res => this%i(idx)
+ end function
+ end module
+
+ use fcn_bar
+ use fcn_mydt
+ integer, target :: a(3) = [1,2,3]
+ integer, pointer :: b
+ integer :: foobar, z, i, ifill(4) = [2, 7, 19, 61], ifill2(2) = [1,2]
+ type(mydt) :: dt
+ foobar (z) = z**2 ! { dg-warning "Obsolescent feature: Statement function" }
+ if (any (a .ne. [1,2,3])) call abort
+
+ ! Assignment to pointer result is after procedure call.
+ foo (a) = 77
+
+ ! Assignment within procedure applies.
+ b => foo (a)
+ if (b .ne. 99) call abort
+
+ ! Use of index for assignment.
+ bar (a, 2) = 99
+ if (any (a .ne. [99,99,3])) call abort
+
+ ! Make sure that statement function still works!
+ if (foobar (10) .ne. 100) call abort
+
+ bar (a, 3) = foobar (9)
+ if (any (a .ne. [99,99,81])) call abort
+
+ ! Try typebound procedure
+ call dt%create (6)
+ dt%elem_fill (3) = 42
+ if (dt%i(3) .ne. 42) call abort
+ dt%elem_fill (3) = 42 + dt%elem_fill (3) ! PR63921 style assignment
+ if (dt%i(3) .ne. 84) call abort
+ dt%elem_fill (3) = dt%elem_fill (3) - dt%elem_fill (3)
+ if (dt%i(3) .ne. 0) call abort
+ ! Array is now reset
+ dt%fill (3) = ifill ! Check with array variable rhs
+ dt%fill (1) = [2,1] ! Check with array constructor rhs
+ if (any (dt%i .ne. [2,1,ifill])) call abort
+ dt%fill (1) = footoo (size (dt%i, 1)) ! Check with array function rhs
+ if (any (dt%i .ne. [6,5,4,3,2,1])) call abort
+ dt%fill (3) = ifill + dt%fill (3) ! Array version of PR63921
assignment
+ if (any (dt%i .ne. [6,5,6,10,21,62])) call abort
+ call dt%delete
+
+ contains
+ function foo (arg)
+ integer, pointer :: foo
+ integer, target :: arg(:)
+ foo => arg (1)
+ foo = 99
+ end function
+ function footoo (arg) result(res)
+ integer :: arg
+ integer :: res(arg)
+ res = [(arg - i, i = 0, arg - 1)]
+ end function
+ end
Index: gcc/testsuite/gfortran.dg/ptr_func_assign_2.f08
===================================================================
*** gcc/testsuite/gfortran.dg/ptr_func_assign_2.f08 (revision 0)
--- gcc/testsuite/gfortran.dg/ptr_func_assign_2.f08 (working copy)
***************
*** 0 ****
--- 1,113 ----
+ ! { dg-do compile }
+ ! { dg-options -std=f2003 }
+ !
+ ! Is a copy of ptr_func_assign_1.f08 with checks for F2008 standard.
+ !
+ ! Contributed by Paul Thomas <[email protected]>
+ !
+ module fcn_bar
+ contains
+ function bar (arg, idx) result (res)
+ integer, pointer :: res
+ integer, target :: arg(:)
+ integer :: idx
+ res => arg (idx)
+ res = 99
+ end function
+ end module
+
+ module fcn_mydt
+ type mydt
+ integer, allocatable, dimension (:) :: i
+ contains
+ procedure, pass :: create
+ procedure, pass :: delete
+ procedure, pass :: fill
+ procedure, pass :: elem_fill
+ end type
+ contains
+ subroutine create (this, sz)
+ class(mydt) :: this
+ integer :: sz
+ if (allocated (this%i)) deallocate (this%i)
+ allocate (this%i(sz))
+ this%i = 0
+ end subroutine
+ subroutine delete (this)
+ class(mydt) :: this
+ if (allocated (this%i)) deallocate (this%i)
+ end subroutine
+ function fill (this, idx) result (res)
+ integer, pointer :: res(:)
+ integer :: lb, ub
+ class(mydt), target :: this
+ integer :: idx
+ lb = idx
+ ub = lb + size(this%i) - 1
+ res => this%i(lb:ub)
+ end function
+ function elem_fill (this, idx) result (res)
+ integer, pointer :: res
+ class(mydt), target :: this
+ integer :: idx
+ res => this%i(idx)
+ end function
+ end module
+
+ use fcn_bar
+ use fcn_mydt
+ integer, target :: a(3) = [1,2,3]
+ integer, pointer :: b
+ integer :: foobar, z, i, ifill(4) = [2, 7, 19, 61], ifill2(2) = [1,2]
+ type(mydt) :: dt
+ foobar (z) = z**2 ! { dg-warning "Obsolescent feature: Statement function" }
+ if (any (a .ne. [1,2,3])) call abort
+
+ ! Assignment to pointer result is after procedure call.
+ foo (a) = 77 ! { dg-error "Unclassifiable statement" }
+
+ ! Assignment within procedure applies.
+ b => foo (a)
+ if (b .ne. 99) call abort
+
+ ! Use of index for assignment.
+ bar (a, 2) = 99 ! { dg-error "is not a variable" }
+ if (any (a .ne. [99,99,3])) call abort
+
+ ! Make sure that statement function still works!
+ if (foobar (10) .ne. 100) call abort
+
+ bar (a, 3) = foobar (9)! { dg-error "is not a variable" }
+ if (any (a .ne. [99,99,81])) call abort
+
+ ! Try typebound procedure
+ call dt%create (6)
+ dt%elem_fill (3) = 42 ! { dg-error "Pointer procedure assignment" }
+ if (dt%i(3) .ne. 42) call abort
+ dt%elem_fill (3) = 42 + dt%elem_fill (3)! { dg-error "Pointer procedure
assignment" }
+ if (dt%i(3) .ne. 84) call abort
+ dt%elem_fill (3) = dt%elem_fill (3) - dt%elem_fill (3)! { dg-error "Pointer
procedure assignment" }
+ if (dt%i(3) .ne. 0) call abort
+ ! Array is now reset
+ dt%fill (3) = ifill ! { dg-error "Pointer procedure assignment" }
+ dt%fill (1) = [2,1] ! { dg-error "Pointer procedure assignment" }
+ if (any (dt%i .ne. [2,1,ifill])) call abort
+ dt%fill (1) = footoo (size (dt%i, 1)) ! { dg-error "Pointer procedure
assignment" }
+ if (any (dt%i .ne. [6,5,4,3,2,1])) call abort
+ dt%fill (3) = ifill + dt%fill (3) ! { dg-error "Pointer procedure
assignment" }
+ if (any (dt%i .ne. [6,5,6,10,21,62])) call abort
+ call dt%delete
+
+ contains
+ function foo (arg)
+ integer, pointer :: foo
+ integer, target :: arg(:)
+ foo => arg (1)
+ foo = 99
+ end function
+ function footoo (arg) result(res)
+ integer :: arg
+ integer :: res(arg)
+ res = [(arg - i, i = 0, arg - 1)]
+ end function
+ end
Index: gcc/testsuite/gfortran.dg/ptr_func_assign_3.f08
===================================================================
*** gcc/testsuite/gfortran.dg/ptr_func_assign_3.f08 (revision 0)
--- gcc/testsuite/gfortran.dg/ptr_func_assign_3.f08 (working copy)
***************
*** 0 ****
--- 1,52 ----
+ ! { dg-do run }
+ !
+ ! Tests corrections to implementation of pointer function assignments.
+ !
+ ! Contributed by Mikael Morin <[email protected]>
+ !
+ module m
+ implicit none
+ type dt
+ integer :: data
+ contains
+ procedure assign_dt
+ generic :: assignment(=) => assign_dt
+ end type
+ contains
+ subroutine assign_dt(too, from)
+ class(dt), intent(out) :: too
+ type(dt), intent(in) :: from
+ too%data = from%data + 1
+ end subroutine
+ end module m
+
+ program p
+ use m
+ integer, parameter :: b = 3
+ integer, target :: a = 2
+ type(dt), target :: tdt
+ type(dt) :: sdt = dt(1)
+
+ func (arg=b) = 1 ! This was rejected as an unclassifiable statement
+ if (a /= 1) call abort
+
+ func (b + b - 3) = -1
+ if (a /= -1) call abort
+
+ dtfunc () = sdt ! Check that defined assignment is resolved
+ if (tdt%data /= 2) call abort
+ contains
+ function func(arg) result(r)
+ integer, pointer :: r
+ integer :: arg
+ if (arg == 3) then
+ r => a
+ else
+ r => null()
+ end if
+ end function func
+ function dtfunc() result (r)
+ type(dt), pointer :: r
+ r => tdt
+ end function
+ end program p
Index: gcc/testsuite/gfortran.dg/ptr_func_assign_4.f08
===================================================================
*** gcc/testsuite/gfortran.dg/ptr_func_assign_4.f08 (revision 0)
--- gcc/testsuite/gfortran.dg/ptr_func_assign_4.f08 (working copy)
***************
*** 0 ****
--- 1,32 ----
+ ! { dg-do compile }
+ !
+ ! Tests correction to implementation of pointer function assignments.
+ !
+ ! Contributed by Mikael Morin <[email protected]>
+ !
+ program p
+ integer, target :: a(3) = 2
+ integer :: b(3, 3) = 1
+ integer :: c
+
+ c = 3
+ func (b(2, 2)) = b ! { dg-error "Different ranks" }
+ func (c) = b ! { dg-error "Different ranks" }
+ func2 (c) = b ! { dg-error "must have the pointer attribute" }
+ contains
+ function func(arg) result(r)
+ integer, pointer :: r(:)
+ integer :: arg
+
+ if (arg == 1) then
+ r => a
+ else
+ r => null()
+ end if
+ end function func
+ function func2(arg) result(r)
+ integer :: r(1)
+ integer :: arg
+ r = 0
+ end function func2
+ end program p