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  <pa...@gcc.gnu.org>

    * 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  <pa...@gcc.gnu.org>

    * 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  <mikael.mo...@sfr.fr>

    * 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
<paul.richard.tho...@gmail.com> 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 <mikael.mo...@sfr.fr> 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
>>> <paul.richard.tho...@gmail.com> 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  <pa...@gcc.gnu.org>
+ !
+ 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  <pa...@gcc.gnu.org>
+ !
+ 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  <mikael.mo...@sfr.fr>
+ !
+ 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  <mikael.mo...@sfr.fr>
+ !
+ 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

Reply via email to