]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fortran: Generic processing of assumed rank objects (f202y) [PR116733]
authorPaul Thomas <pault@gcc.gnu.org>
Wed, 23 Oct 2024 13:34:20 +0000 (14:34 +0100)
committerPaul Thomas <pault@gcc.gnu.org>
Wed, 23 Oct 2024 13:34:59 +0000 (14:34 +0100)
2024-10-23  Paul Thomas  <pault@gcc.gnu.org>

gcc/fortran
PR fortran/116733
* array.cc : White space corrections.
* expr.cc (gfc_check_pointer_assign): Permit assumed rank
target with -std=f202y. Add constraints that the data pointer
object must have rank remapping specified and the that the data
target be contiguous.
* gfortran.h : Add a gfc_array_ref field 'ar' to the structure
'gfc_association_list'.
* interface.cc (gfc_compare_actual_formal): If -Wsurprising
is set, emit a warning if an assumed size array is passed to an
assumed rank dummy.
* intrinsic.cc (do_ts29113_check): Permit an assumed rank arg.
for reshape if -std=f202y and the argument is contiguous.
* invoke.texi : Introduce -std=f202y. Whitespace errors.
* lang.opt : Accept -std=f202y.
* libgfortran.h : Define GFC_STD_F202Y.
* match.cc (gfc_match_associate): If -std=f202y an assumed rank
selector is allowed if it is contiguous and the associate name
has rank remapping specified.
* options.cc (gfc_init_options): -std=f202y is equivalent to
-std=f2023 with experimental f202y features. White space issues
* parse.cc (parse_associate): If the selector is assumed rank,
use the 'ar' field of the association list to build an array
specification.
* primary.cc (gfc_match_varspec): Do not resolve the assumed
rank selector of a class associate name at this stage to avoid
the rank change.
* resolve.cc (find_array_spec): If an array_ref dimension is -1
reset it with the rank in the object's array_spec.
(gfc_expression_rank): Do not check dimen types for an assumed
rank variable expression.
(resolve_variable): Do not emit the assumed rank context error
if the context is pointer assignment and the variable is a
target.
(resolve_assoc_var): Resolve the bounds and check for missing
bounds in the rank remap of an associate name with an assumed
rank selector. Do not correct the rank of an associate name
with an assumed rank selector.
(resolve_symbol): Allow the reference to an assumed rank object
if -std-f202y is enabled and the current operation is
EXEC_BLOCK.
* st.cc (gfc_free_association_list): Free bounds expressions
of the 'ar' field, if present.
* trans-array.cc (gfc_conv_ss_startstride): If -std=f202y and
bounds checking activated, do not apply the assertion.
* trans-expr.cc (gfc_trans_pointer_assignment): An assumed rank
target has its offset set to zero.
* trans-stmt.cc (trans_associate_var): If the selector is
assumed rank, call gfc_trans_pointer_assignment using the 'ar'
field in the association list as the array reference for expr1.
The data target, expr2, is a copy of the selector expression.

gcc/testsuite/
PR fortran/116733
* gfortran.dg/associate_3.f03: Change error message.
* gfortran.dg/f202y/f202y.exp: Enable tests of f202y features.
* gfortran.dg/f202y/generic_assumed_rank_1.f90: New test.
* gfortran.dg/f202y/generic_assumed_rank_2.f90: New test.
* gfortran.dg/f202y/generic_assumed_rank_3.f90: New test.

22 files changed:
gcc/fortran/array.cc
gcc/fortran/expr.cc
gcc/fortran/gfortran.h
gcc/fortran/interface.cc
gcc/fortran/intrinsic.cc
gcc/fortran/invoke.texi
gcc/fortran/lang.opt
gcc/fortran/libgfortran.h
gcc/fortran/match.cc
gcc/fortran/options.cc
gcc/fortran/parse.cc
gcc/fortran/primary.cc
gcc/fortran/resolve.cc
gcc/fortran/st.cc
gcc/fortran/trans-array.cc
gcc/fortran/trans-expr.cc
gcc/fortran/trans-stmt.cc
gcc/testsuite/gfortran.dg/associate_3.f03
gcc/testsuite/gfortran.dg/f202y/f202y.exp [new file with mode: 0644]
gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_3.f90 [new file with mode: 0644]

index 773c5b72c851541253bda60809d7d92c1b326b5e..6dedaed3d4d1e56bcbf94f7d2af52af965ca7223 100644 (file)
@@ -869,7 +869,7 @@ gfc_set_array_spec (gfc_symbol *sym, gfc_array_spec *as, locus *error_loc)
 {
   int i;
   symbol_attribute *attr;
-  
+
   if (as == NULL)
     return true;
 
@@ -878,7 +878,7 @@ gfc_set_array_spec (gfc_symbol *sym, gfc_array_spec *as, locus *error_loc)
   attr = &sym->attr;
   if (gfc_submodule_procedure(attr))
     return true;
-  
+
   if (as->rank
       && !gfc_add_dimension (&sym->attr, sym->name, error_loc))
     return false;
@@ -2457,7 +2457,7 @@ gfc_ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result, mpz_t *end)
        mpz_set_ui (stride, 1);
       else
        {
-         stride_expr = gfc_copy_expr(ar->stride[dimen]); 
+         stride_expr = gfc_copy_expr(ar->stride[dimen]);
 
          if (!gfc_simplify_expr (stride_expr, 1)
             || stride_expr->expr_type != EXPR_CONSTANT
index 65bb9f11815e538f5a195a648483d8d02b7d179b..b3e0bf1fd91a94b035ad42b699904b01e729044c 100644 (file)
@@ -4371,9 +4371,18 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue,
          return false;
        }
 
+      /* An assumed rank target is an experimental F202y feature.  */
+      if (rvalue->rank == -1 && !(gfc_option.allow_std & GFC_STD_F202Y))
+       {
+         gfc_error ("The assumed rank target at %L is an experimental F202y "
+                    "feature. Use option -std=f202y to enable",
+                    &rvalue->where);
+         return false;
+       }
+
       /* The target must be either rank one or it must be simply contiguous
         and F2008 must be allowed.  */
-      if (rvalue->rank != 1)
+      if (rvalue->rank != 1 && rvalue->rank != -1)
        {
          if (!gfc_is_simply_contiguous (rvalue, true, false))
            {
@@ -4386,6 +4395,21 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue,
            return false;
        }
     }
+  else if (rvalue->rank == -1)
+    {
+      gfc_error ("The data-target at %L is an assumed rank object and so the "
+                "data-pointer-object %s must have a bounds remapping list "
+                "(list of lbound:ubound for each dimension)",
+                 &rvalue->where, lvalue->symtree->name);
+      return false;
+    }
+
+  if (rvalue->rank == -1 && !gfc_is_simply_contiguous (rvalue, true, false))
+    {
+      gfc_error ("The assumed rank data-target at %L must be contiguous",
+                &rvalue->where);
+      return false;
+    }
 
   /* Now punt if we are dealing with a NULLIFY(X) or X = NULL(X).  */
   if (rvalue->expr_type == EXPR_NULL)
index 9e81a81686c606a92e195fc7b20ed49421154a70..a55646d5604eabf9f7996ce1223a7e97f3f86930 100644 (file)
@@ -3034,6 +3034,8 @@ typedef struct gfc_association_list
 
   gfc_expr *target;
 
+  gfc_array_ref *ar;
+
   /* Used for inferring the derived type of an associate name, whose selector
      is a sibling derived type function that has not yet been parsed.  */
   gfc_symbol *derived_types;
index b592fe4f6c7f36a229feb059a3ea93cff88202d5..dbcbed8bf30cc833d461f585dedf615b0276c43f 100644 (file)
@@ -3337,6 +3337,16 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
          goto match;
        }
 
+      if (warn_surprising
+         && a->expr->expr_type == EXPR_VARIABLE
+         && a->expr->symtree->n.sym->as
+         && a->expr->symtree->n.sym->as->type == AS_ASSUMED_SIZE
+         && f->sym->as
+         && f->sym->as->type == AS_ASSUMED_RANK)
+       gfc_warning (0, "The assumed-size dummy %qs is being passed at %L to "
+                    "an assumed-rank dummy %qs", a->expr->symtree->name,
+                    &a->expr->where, f->sym->name);
+
       if (a->expr->expr_type == EXPR_NULL
          && a->expr->ts.type == BT_UNKNOWN
          && f->sym->ts.type == BT_CHARACTER
index c6fb0a6de45a6369199f3a910f2d67db0024d6d4..114f1b6c0458b362f9b7204995d4c9bd3dc697c5 100644 (file)
@@ -293,11 +293,15 @@ do_ts29113_check (gfc_intrinsic_sym *specific, gfc_actual_arglist *arg)
                     &a->expr->where, gfc_current_intrinsic);
          ok = false;
        }
-      else if (a->expr->rank == -1 && !specific->inquiry)
+      else if (a->expr->rank == -1
+              && !(specific->inquiry
+                   || (specific->id == GFC_ISYM_RESHAPE
+                       && (gfc_option.allow_std & GFC_STD_F202Y))))
        {
          gfc_error ("Assumed-rank argument at %L is only permitted as actual "
-                    "argument to intrinsic inquiry functions",
-                    &a->expr->where);
+                    "argument to intrinsic inquiry functions or to RESHAPE. "
+                    "The latter is an experimental F202y feature. Use "
+                    "-std=f202y to enable", &a->expr->where);
          ok = false;
        }
       else if (a->expr->rank == -1 && arg != a)
@@ -307,6 +311,13 @@ do_ts29113_check (gfc_intrinsic_sym *specific, gfc_actual_arglist *arg)
                     &a->expr->where, gfc_current_intrinsic);
          ok = false;
        }
+      else if (a->expr->rank == -1 && specific->id == GFC_ISYM_RESHAPE
+              && !gfc_is_simply_contiguous (a->expr, true, false))
+       {
+         gfc_error ("Assumed rank argument to the RESHAPE intrinsic at %L "
+                    "must be contiguous", &a->expr->where);
+         ok = false;
+       }
     }
 
   return ok;
index a9ac87d3a32f64cdd894d1eae4285c16471cd434..fc6a8c6d07f398e7a0cb41fcdba47c77de928d97 100644 (file)
@@ -1,5 +1,5 @@
 @c Copyright (C) 2004-2024 Free Software Foundation, Inc.
-@c This is part of the GNU Fortran manual.   
+@c This is part of the GNU Fortran manual.
 @c For copying conditions, see the file gfortran.texi.
 
 @ignore
@@ -139,7 +139,7 @@ by type.  Explanations are in the following sections.
 -H -P
 -U@var{macro} -cpp -dD -dI -dM -dN -dU -fworking-directory
 -imultilib @var{dir}
--iprefix @var{file} -iquote -isysroot @var{dir} -isystem @var{dir} -nocpp 
+-iprefix @var{file} -iquote -isysroot @var{dir} -isystem @var{dir} -nocpp
 -nostdinc
 -undef
 }
@@ -312,7 +312,7 @@ JIAND, etc...). For a complete list of intrinsics see the full documentation.
 Obsolete flag.  The purpose of this option was to
 enable legacy math intrinsics such as COTAN and degree-valued trigonometric
 functions (e.g. TAND, ATAND, etc...) for compatability with older code. This
-option is no longer operable. The trigonometric functions are now either 
+option is no longer operable. The trigonometric functions are now either
 part of Fortran 2023 or GNU extensions.
 
 @opindex fdec-static
@@ -341,7 +341,7 @@ following the final comma.
 @cindex symbol names
 @cindex character set
 @item -fdollar-ok
-Allow @samp{$} as a valid non-first character in a symbol name. Symbols 
+Allow @samp{$} as a valid non-first character in a symbol name. Symbols
 that start with @samp{$} are rejected since it is unclear which rules to
 apply to implicit typing as different vendors implement different rules.
 Using @samp{$} in @code{IMPLICIT} statements is also rejected.
@@ -606,7 +606,10 @@ beyond the relevant language standard, and warnings are given for the
 Fortran 77 features that are permitted but obsolescent in later
 standards. The deprecated option @samp{-std=f2008ts} acts as an alias for
 @samp{-std=f2018}. It is only present for backwards compatibility with
-earlier gfortran versions and should not be used any more.
+earlier gfortran versions and should not be used any more. @samp{-std=f202y}
+acts as an alias for @samp{-std=f2023} and enables proposed features for
+testing Fortran 202y. As the Fortran 202y standard develops, implementation
+might change or the experimental new features might be removed.
 
 @opindex ftest-forall-temp
 @item -ftest-forall-temp
@@ -718,7 +721,7 @@ Like @option{-dD}, but emit only the macro names, not their expansions.
 @cindex debugging, preprocessor
 @item -dU
 Like @option{dD} except that only macros that are expanded, or whose
-definedness is tested in preprocessor directives, are output; the 
+definedness is tested in preprocessor directives, are output; the
 output is delayed until the use or test of the macro; and @code{'#undef'}
 directives are also output for macros tested but undefined at the time.
 
@@ -908,7 +911,7 @@ with a @option{-D} option.
 Errors are diagnostic messages that report that the GNU Fortran compiler
 cannot compile the relevant piece of source code.  The compiler will
 continue to process the program in an attempt to report further errors
-to aid in debugging, but will not produce any compiled output.  
+to aid in debugging, but will not produce any compiled output.
 
 Warnings are diagnostic messages that report constructions which
 are not inherently erroneous but which are risky or suggest there is
@@ -1027,7 +1030,7 @@ avoid such temporaries.
 @opindex Wc-binding-type
 @cindex warning, C binding type
 @item -Wc-binding-type
-Warn if the a variable might not be C interoperable.  In particular, warn if 
+Warn if the a variable might not be C interoperable.  In particular, warn if
 the variable has been declared using an intrinsic type with default kind
 instead of using a kind parameter defined for C interoperability in the
 intrinsic @code{ISO_C_Binding} module.  This option is implied by
@@ -1050,7 +1053,7 @@ error.
 @cindex warnings, conversion
 @cindex conversion
 @item -Wconversion
-Warn about implicit conversions that are likely to change the value of 
+Warn about implicit conversions that are likely to change the value of
 the expression after conversion. Implied by @option{-Wall}.
 
 @opindex Wconversion-extra
@@ -1191,7 +1194,7 @@ the desired intrinsic/procedure.  This option is implied by @option{-Wall}.
 @cindex warnings, use statements
 @cindex intrinsic
 @item -Wuse-without-only
-Warn if a @code{USE} statement has no @code{ONLY} qualifier and 
+Warn if a @code{USE} statement has no @code{ONLY} qualifier and
 thus implicitly imports all public entities of the used module.
 
 @opindex Wunused-dummy-argument
@@ -1436,8 +1439,8 @@ they are not in the default location expected by the compiler.
 @cindex options, linking
 @cindex linking, static
 
-These options come into play when the compiler links object files into an 
-executable output file. They are meaningless if the compiler is not doing 
+These options come into play when the compiler links object files into an
+executable output file. They are meaningless if the compiler is not doing
 a link step.
 
 @table @gcctabopt
@@ -1609,7 +1612,7 @@ referenced in it. Does not affect common blocks. (Some Fortran compilers
 provide this option under the name @option{-static} or @option{-save}.)
 The default, which is @option{-fautomatic}, uses the stack for local
 variables smaller than the value given by @option{-fmax-stack-var-size}.
-Use the option @option{-frecursive} to use no static memory. 
+Use the option @option{-frecursive} to use no static memory.
 
 Local variables or arrays having an explicit @code{SAVE} attribute are
 silently ignored unless the @option{-pedantic} option is added.
@@ -1880,7 +1883,7 @@ Deprecated alias for @option{-fcheck=array-temps}.
 
 @opindex fmax-array-constructor
 @item -fmax-array-constructor=@var{n}
-This option can be used to increase the upper limit permitted in 
+This option can be used to increase the upper limit permitted in
 array constructors.  The code below requires this option to expand
 the array at compile time.
 
index 00a16ed167af6e07bbdb35b6845c811f61a10475..f2589a45cae6012a5b4e63122ddf1ed082ffe498 100644 (file)
@@ -7,12 +7,12 @@
 ; 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/>.
@@ -930,6 +930,10 @@ std=f2023
 Fortran
 Conform to the ISO Fortran 2023 standard.
 
+std=f202y
+Fortran
+Enable experimental Fortran 202y features.
+
 std=f95
 Fortran
 Conform to the ISO Fortran 95 standard.
index 773f2a0b049ff4bfcffdb9710d060bbf0c8b67c2..9e786dd942133551d7e6ad392b6f68daf225f670 100644 (file)
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
    Nevertheless, some features available in F2018 are prohibited in F2023.
    Please remember to keep those definitions in sync with
    gfortran.texi.  */
+#define GFC_STD_F202Y          (1<<14) /* Enable proposed F202y features.  */
 #define GFC_STD_UNSIGNED       (1<<14) /* Not really a standard, but
                                           better for error handling.  */
 #define GFC_STD_F2023_DEL      (1<<13) /* Prohibited in F2023.  */
index 3a993ede880b464d38bd3b10b698c096b45ef96a..2b3ed4f4cf532cd49133500db260026b40bbb39a 100644 (file)
@@ -1925,7 +1925,29 @@ gfc_match_associate (void)
       gfc_association_list* a;
 
       /* Match the next association.  */
-      if (gfc_match (" %n =>", newAssoc->name) != MATCH_YES)
+      if (gfc_match (" %n ", newAssoc->name) != MATCH_YES)
+       {
+         gfc_error ("Expected associate name at %C");
+         goto assocListError;
+       }
+
+      /* Required for an assumed rank target.  */
+      if (gfc_peek_char () == '(')
+       {
+         newAssoc->ar = gfc_get_array_ref ();
+         if (gfc_match_array_ref (newAssoc->ar, NULL, 0, 0) != MATCH_YES)
+           {
+             gfc_error ("Bad bounds remapping list at %C");
+             goto assocListError;
+           }
+       }
+
+      if (newAssoc->ar && !(gfc_option.allow_std & GFC_STD_F202Y))
+       gfc_error_now ("The bounds remapping list at %C is an experimental "
+                      "F202y feature. Use std=f202y to enable");
+
+      /* Match the next association.  */
+      if (gfc_match (" =>", newAssoc->name) != MATCH_YES)
        {
          gfc_error ("Expected association at %C");
          goto assocListError;
@@ -1969,6 +1991,35 @@ gfc_match_associate (void)
          goto assocListError;
        }
 
+      if (newAssoc->target->expr_type == EXPR_VARIABLE
+         && newAssoc->target->symtree->n.sym->as
+         && newAssoc->target->symtree->n.sym->as->type == AS_ASSUMED_RANK)
+       {
+         bool bounds_remapping_list = true;
+         if (!newAssoc->ar)
+           bounds_remapping_list = false;
+         else
+           for (int dim = 0; dim < newAssoc->ar->dimen; dim++)
+             if (!newAssoc->ar->start[dim] || !newAssoc->ar->end[dim]
+                 || newAssoc->ar->stride[dim] != NULL)
+               bounds_remapping_list = false;
+
+         if (!bounds_remapping_list)
+           {
+             gfc_error ("The associate name %s with an assumed rank "
+                        "target at %L must have a bounds remapping list "
+                        "(list of lbound:ubound for each dimension)",
+                        newAssoc->name, &newAssoc->target->where);
+             goto assocListError;
+           }
+
+         if (!newAssoc->target->symtree->n.sym->attr.contiguous)
+           {
+             gfc_error ("The assumed rank target at %C must be contiguous");
+             goto assocListError;
+           }
+       }
+
       /* The `variable' field is left blank for now; because the target is not
         yet resolved, we can't use gfc_has_vector_subscript to determine it
         for now.  This is set during resolution.  */
index a55f1f36f3f9ac5f4bdceff8bbf43c2d7d605876..0004df9278b866824cc5a09333e1201340e9b2e5 100644 (file)
@@ -156,7 +156,7 @@ gfc_init_options (unsigned int decoded_options_count,
   gfc_option.flag_preprocessed = 0;
   gfc_option.flag_d_lines = -1;
   set_init_local_zero (0);
-  
+
   gfc_option.fpe = 0;
   /* All except GFC_FPE_INEXACT.  */
   gfc_option.fpe_summary = GFC_FPE_INVALID | GFC_FPE_DENORMAL
@@ -383,7 +383,7 @@ gfc_post_options (const char **pfilename)
        {
          gfc_current_form = FORM_FREE;
          main_input_filename = filename;
-         gfc_warning_now (0, "Reading file %qs as free form", 
+         gfc_warning_now (0, "Reading file %qs as free form",
                           (filename[0] == '\0') ? "<stdin>" : filename);
        }
     }
@@ -647,7 +647,7 @@ gfc_handle_runtime_check_option (const char *arg)
                                 GFC_RTCHECK_RECURSION, GFC_RTCHECK_DO,
                                 GFC_RTCHECK_POINTER, GFC_RTCHECK_MEM,
                                 GFC_RTCHECK_BITS, 0 };
+
   while (*arg)
     {
       while (*arg == ',')
@@ -708,7 +708,7 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
     case OPT_fcheck_array_temporaries:
       SET_BITFLAG (gfc_option.rtcheck, value, GFC_RTCHECK_ARRAY_TEMPS);
       break;
-      
+
     case OPT_fd_lines_as_code:
       gfc_option.flag_d_lines = 1;
       break;
@@ -845,6 +845,15 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       warn_tabs = 1;
       break;
 
+    case OPT_std_f202y:
+      gfc_option.allow_std = GFC_STD_OPT_F23 | GFC_STD_F202Y;
+      gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F2008_OBS
+       | GFC_STD_F2018_OBS;
+      gfc_option.max_identifier_length = 63;
+      warn_ampersand = 1;
+      warn_tabs = 1;
+      break;
+
     case OPT_std_gnu:
       set_default_std_flags ();
       break;
@@ -883,10 +892,10 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 
     }
 
-  Fortran_handle_option_auto (&global_options, &global_options_set, 
-                              scode, arg, value, 
-                              gfc_option_lang_mask (), kind,
-                              loc, handlers, global_dc);
+  Fortran_handle_option_auto (&global_options, &global_options_set,
+                             scode, arg, value,
+                             gfc_option_lang_mask (), kind,
+                             loc, handlers, global_dc);
   return result;
 }
 
@@ -933,7 +942,7 @@ gfc_get_option_string (void)
 
   result = XCNEWVEC (char, len);
 
-  pos = 0; 
+  pos = 0;
   for (j = 1; j < save_decoded_options_count; j++)
     {
       switch (save_decoded_options[j].opt_index)
index 1821871819bc3720bffcd9f56cdff0642439d582..d2fe22d0edc6bfcb36e6b2f974d9bea69b2a06ec 100644 (file)
@@ -5285,15 +5285,25 @@ parse_associate (void)
          if ((!CLASS_DATA (sym)->as && (rank != 0 || corank != 0))
              || (CLASS_DATA (sym)->as
                  && (CLASS_DATA (sym)->as->rank != rank
-                     || CLASS_DATA (sym)->as->corank != corank)))
+                     || CLASS_DATA (sym)->as->corank != corank))
+             || rank == -1)
            {
              /* Don't just (re-)set the attr and as in the sym.ts,
              because this modifies the target's attr and as.  Copy the
              data and do a build_class_symbol.  */
              symbol_attribute attr = CLASS_DATA (target)->attr;
              gfc_typespec type;
-
-             if (rank || corank)
+             if (rank == -1 && a->ar)
+               {
+                 as = gfc_get_array_spec ();
+                 as->rank = a->ar->dimen;
+                 as->corank = 0;
+                 as->type = AS_DEFERRED;
+                 attr.dimension = rank ? 1 : 0;
+                 attr.codimension = as->corank ? 1 : 0;
+                 sym->assoc->variable = true;
+               }
+              else if (rank || corank)
                {
                  as = gfc_get_array_spec ();
                  as->type = AS_DEFERRED;
@@ -5319,6 +5329,16 @@ parse_associate (void)
          else
            sym->attr.class_ok = 1;
        }
+      else if (rank == -1 && a->ar)
+       {
+         sym->as = gfc_get_array_spec ();
+         sym->as->rank = a->ar->dimen;
+         sym->as->corank = a->ar->codimen;
+         sym->as->type = AS_DEFERRED;
+         sym->attr.dimension = 1;
+         sym->attr.codimension = sym->as->corank ? 1 : 0;
+         sym->attr.pointer = 1;
+       }
       else if ((!sym->as && (rank != 0 || corank != 0))
               || (sym->as
                   && (sym->as->rank != rank || sym->as->corank != corank)))
@@ -5336,6 +5356,7 @@ parse_associate (void)
              sym->attr.codimension = 1;
            }
        }
+      gfc_commit_symbols ();
     }
 
   accept_statement (ST_ASSOCIATE);
index b93ee56fb357b545d9f5e7a5843141def62451dc..e57f631eff42b368f2a398fc6a4cf14c0814f92f 100644 (file)
@@ -2276,6 +2276,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
        }
     }
   else if (sym->ts.type == BT_CLASS
+          && !(sym->assoc && sym->assoc->ar)
           && tgt_expr
           && tgt_expr->expr_type == EXPR_VARIABLE
           && sym->ts.u.derived != tgt_expr->ts.u.derived)
index ce4bf036c54508a4a2ac8ea5c5fb0971857e8119..c96523e4ad58d278125ea851e0cf72b5ae72d45b 100644 (file)
@@ -5204,6 +5204,7 @@ find_array_spec (gfc_expr *e)
          }
 
        ref->u.ar.as = as;
+       if (ref->u.ar.dimen == -1) ref->u.ar.dimen = as->rank;
        as = NULL;
        break;
 
@@ -5808,7 +5809,8 @@ gfc_expression_rank (gfc_expr *e)
          break;
        }
     }
-  if (last_arr_ref && last_arr_ref->u.ar.as)
+  if (last_arr_ref && last_arr_ref->u.ar.as
+      && last_arr_ref->u.ar.as->rank != -1)
     {
       for (i = last_arr_ref->u.ar.as->rank;
           i < last_arr_ref->u.ar.as->rank + last_arr_ref->u.ar.as->corank; ++i)
@@ -5952,12 +5954,14 @@ resolve_variable (gfc_expr *e)
             && CLASS_DATA (sym)->as
             && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK)
            || (sym->ts.type != BT_CLASS && sym->as
-               && sym->as->type == AS_ASSUMED_RANK))
-          && !sym->attr.select_rank_temporary)
+               && sym->as->type == AS_ASSUMED_RANK))
+          && !sym->attr.select_rank_temporary
+          && !(sym->assoc && sym->assoc->ar))
     {
       if (!actual_arg
          && !(cs_base && cs_base->current
-              && cs_base->current->op == EXEC_SELECT_RANK))
+              && (cs_base->current->op == EXEC_SELECT_RANK
+                  || sym->attr.target)))
        {
          gfc_error ("Assumed-rank variable %s at %L may only be used as "
                     "actual argument", sym->name, &e->where);
@@ -6001,6 +6005,7 @@ resolve_variable (gfc_expr *e)
        && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK)
        || (sym->ts.type != BT_CLASS && sym->as
           && sym->as->type == AS_ASSUMED_RANK))
+      && !(sym->assoc && sym->assoc->ar)
       && e->ref
       && !(e->ref->type == REF_ARRAY && e->ref->u.ar.type == AR_FULL
           && e->ref->next == NULL))
@@ -6117,6 +6122,7 @@ resolve_variable (gfc_expr *e)
       newref->type = REF_ARRAY;
       newref->u.ar.type = AR_FULL;
       newref->u.ar.dimen = 0;
+
       /* Because this is an associate var and the first ref either is a ref to
         the _data component or not, no traversal of the ref chain is
         needed.  The array ref needs to be inserted after the _data ref,
@@ -9558,6 +9564,22 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
   if (resolve_target && !gfc_resolve_expr (target))
     return;
 
+  if (sym->assoc->ar)
+    {
+      int dim;
+      gfc_array_ref *ar = sym->assoc->ar;
+      for (dim = 0; dim < sym->assoc->ar->dimen; dim++)
+       {
+         if (!(ar->start[dim] && gfc_resolve_expr (ar->start[dim])
+               && ar->start[dim]->ts.type == BT_INTEGER)
+             || !(ar->end[dim] && gfc_resolve_expr (ar->end[dim])
+                  && ar->end[dim]->ts.type == BT_INTEGER))
+           gfc_error ("(F202y)Missing or invalid bound in ASSOCIATE rank "
+                      "remapping of associate name %s at %L",
+                      sym->name, &sym->declared_at);
+       }
+    }
+
   /* For variable targets, we get some attributes from the target.  */
   if (target->expr_type == EXPR_VARIABLE)
     {
@@ -9747,7 +9769,7 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
   if (target->ts.type == BT_CLASS)
     gfc_fix_class_refs (target);
 
-  if ((target->rank != 0 || target->corank != 0)
+  if ((target->rank > 0 || target->corank > 0)
       && !sym->attr.select_rank_temporary)
     {
       gfc_array_spec *as;
@@ -16746,7 +16768,9 @@ resolve_symbol (gfc_symbol *sym)
       if (as->type == AS_ASSUMED_RANK && !sym->attr.dummy
          && !sym->attr.select_type_temporary
          && !(cs_base && cs_base->current
-              && cs_base->current->op == EXEC_SELECT_RANK))
+              && (cs_base->current->op == EXEC_SELECT_RANK
+                  || ((gfc_option.allow_std & GFC_STD_F202Y)
+                       && cs_base->current->op == EXEC_BLOCK))))
        {
          gfc_error ("Assumed-rank array at %L must be a dummy argument",
                     &sym->declared_at);
index 904b00080705b6b60468a18b1f3c1d626dbcd418..48e4258d10d2b902313d839cc95ac1eedd16b568 100644 (file)
@@ -335,6 +335,22 @@ gfc_free_association_list (gfc_association_list* assoc)
   if (!assoc)
     return;
 
+  if (assoc->ar)
+    {
+      for (int i = 0; i < assoc->ar->dimen; i++)
+       {
+         if (assoc->ar->start[i]
+             && assoc->ar->start[i]->ts.type == BT_INTEGER)
+           gfc_free_expr (assoc->ar->start[i]);
+         if (assoc->ar->end[i]
+             && assoc->ar->end[i]->ts.type == BT_INTEGER)
+           gfc_free_expr (assoc->ar->end[i]);
+         if (assoc->ar->stride[i]
+             && assoc->ar->stride[i]->ts.type == BT_INTEGER)
+           gfc_free_expr (assoc->ar->stride[i]);
+       }
+    }
+
   gfc_free_association_list (assoc->next);
   free (assoc);
 }
index dbf7bc880a40d81451feceb54be1992f19b93614..ec7728cb11a797b5cd89ebc98113e602064430b3 100644 (file)
@@ -5045,9 +5045,12 @@ done:
                    se.descriptor_only = 1;
                    gfc_conv_expr (&se, arg);
                    /* This is a bare variable, so there is no preliminary
-                      or cleanup code.  */
-                   gcc_assert (se.pre.head == NULL_TREE
-                               && se.post.head == NULL_TREE);
+                      or cleanup code unless -std=f202y and bounds checking
+                      is on.  */
+                   if (!((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
+                         && (gfc_option.allow_std & GFC_STD_F202Y)))
+                     gcc_assert (se.pre.head == NULL_TREE
+                                 && se.post.head == NULL_TREE);
                    rank = gfc_conv_descriptor_rank (se.expr);
                    tmp = fold_build2_loc (input_location, MINUS_EXPR,
                                           gfc_array_index_type,
index 735ab3a21e77c60c1653cbb7b6fb2245b4cc5c20..16feff4952700db6ca18104d46b63117fd340861 100644 (file)
@@ -3253,6 +3253,31 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
        se->expr = gfc_conv_descriptor_data_get (se->expr);
     }
 
+  /* F202Y: Runtime warning that an assumed rank object is associated
+     with an assumed size object.  */
+  if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
+      && (gfc_option.allow_std & GFC_STD_F202Y)
+      && expr->rank == -1 && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se->expr)))
+    {
+      tree dim, lower, upper, cond;
+      char *msg;
+
+      dim = fold_convert (signed_char_type_node,
+                         gfc_conv_descriptor_rank (se->expr));
+      dim = fold_build2_loc (input_location, MINUS_EXPR, signed_char_type_node,
+                            dim, build_int_cst (signed_char_type_node, 1));
+      lower = gfc_conv_descriptor_lbound_get (se->expr, dim);
+      upper = gfc_conv_descriptor_ubound_get (se->expr, dim);
+
+      msg = xasprintf ("Assumed rank object %s is associated with an "
+                      "assumed size object", sym->name);
+      cond = fold_build2_loc (input_location, LT_EXPR,
+                             logical_type_node, upper, lower);
+      gfc_trans_runtime_check (false, true, cond, &se->pre,
+                              &gfc_current_locus, msg);
+      free (msg);
+    }
+
   /* Some expressions leak through that haven't been fixed up.  */
   if (IS_INFERRED_TYPE (expr) && expr->ref)
     gfc_fixup_inferred_type_refs (expr);
@@ -10830,20 +10855,26 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
 
              /* Copy offset but adjust it such that it would correspond
                 to a lbound of zero.  */
-             offs = gfc_conv_descriptor_offset_get (rse.expr);
-             for (dim = 0; dim < expr2->rank; ++dim)
+             if (expr2->rank == -1)
+               gfc_conv_descriptor_offset_set (&block, desc,
+                                               gfc_index_zero_node);
+             else
                {
-                 stride = gfc_conv_descriptor_stride_get (rse.expr,
-                                                          gfc_rank_cst[dim]);
-                 lbound = gfc_conv_descriptor_lbound_get (rse.expr,
-                                                          gfc_rank_cst[dim]);
-                 tmp = fold_build2_loc (input_location, MULT_EXPR,
-                                        gfc_array_index_type, stride, lbound);
-                 offs = fold_build2_loc (input_location, PLUS_EXPR,
-                                         gfc_array_index_type, offs, tmp);
+                 offs = gfc_conv_descriptor_offset_get (rse.expr);
+                 for (dim = 0; dim < expr2->rank; ++dim)
+                   {
+                     stride = gfc_conv_descriptor_stride_get (rse.expr,
+                                                       gfc_rank_cst[dim]);
+                     lbound = gfc_conv_descriptor_lbound_get (rse.expr,
+                                                       gfc_rank_cst[dim]);
+                     tmp = fold_build2_loc (input_location, MULT_EXPR,
+                                            gfc_array_index_type, stride,
+                                            lbound);
+                     offs = fold_build2_loc (input_location, PLUS_EXPR,
+                                             gfc_array_index_type, offs, tmp);
+                   }
+                 gfc_conv_descriptor_offset_set (&block, desc, offs);
                }
-             gfc_conv_descriptor_offset_set (&block, desc, offs);
-
              /* Set the bounds as declared for the LHS and calculate strides as
                 well as another offset update accordingly.  */
              stride = gfc_conv_descriptor_stride_get (rse.expr,
@@ -10855,6 +10886,13 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
 
                  gcc_assert (remap->u.ar.start[dim] && remap->u.ar.end[dim]);
 
+                 if (remap->u.ar.start[dim]->expr_type != EXPR_CONSTANT
+                     || remap->u.ar.start[dim]->expr_type != EXPR_VARIABLE)
+                   gfc_resolve_expr (remap->u.ar.start[dim]);
+                 if (remap->u.ar.end[dim]->expr_type != EXPR_CONSTANT
+                     || remap->u.ar.end[dim]->expr_type != EXPR_VARIABLE)
+                   gfc_resolve_expr (remap->u.ar.end[dim]);
+
                  /* Convert declared bounds.  */
                  gfc_init_se (&lower_se, NULL);
                  gfc_init_se (&upper_se, NULL);
@@ -10930,7 +10968,8 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
 
       /* If rank remapping was done, check with -fcheck=bounds that
         the target is at least as large as the pointer.  */
-      if (rank_remap && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS))
+      if (rank_remap && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
+         && expr2->rank != -1)
        {
          tree lsize, rsize;
          tree fault;
index 81d9740b5655dd313efe163a0c9352f50911394f..e1a84f228282062807a2e59bdab6f155fa586b43 100644 (file)
@@ -1908,7 +1908,53 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
 
       gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), tmp);
     }
+
   /* Now all the other kinds of associate variable.  */
+
+  /* First we do the F202y ASSOCIATE construct with an assumed rank selector.
+     Since this requires rank remapping, the simplest implementation builds an
+     array reference, using the array ref attached to the association_list,
+     followed by gfc_trans_pointer_assignment.  */
+  else if (e->rank == -1 && sym->assoc->ar)
+    {
+      gfc_array_ref *ar;
+      gfc_expr *expr1 = gfc_lval_expr_from_sym (sym);
+      stmtblock_t init;
+      gfc_init_block (&init);
+
+      /* Build the array reference and add to expr1.  */
+      gfc_free_ref_list (expr1->ref);
+      expr1->ref = gfc_get_ref();
+      expr1->ref->type = REF_ARRAY;
+      ar = gfc_copy_array_ref (sym->assoc->ar);
+      expr1->ref->u.ar = *ar;
+      expr1->ref->u.ar.type = AR_SECTION;
+
+      /* For class objects, insert the _data component reference. Since the
+        associate-name is a pointer, it needs a target, which is created using
+        its typespec. If unlimited polymorphic, the _len field will be filled
+        by the pointer assignment.  */
+      if (expr1->ts.type == BT_CLASS)
+       {
+         need_len_assign = false;
+         gfc_ref *ref;
+         gfc_find_component (expr1->ts.u.derived, "_data", true, true, &ref);
+         ref->next = expr1->ref;
+         expr1->ref = ref;
+         expr1->rank = CLASS_DATA (sym)->as->rank;
+         tmp = gfc_create_var (gfc_typenode_for_spec (&sym->ts), "class");
+         tmp = gfc_build_addr_expr (NULL_TREE, tmp);
+         gfc_add_modify (&init, sym->backend_decl, tmp);
+       }
+
+      /* Do the pointer assignment and clean up.  */
+      gfc_expr *expr2 = gfc_copy_expr (e);
+      gfc_add_expr_to_block (&init,
+                            gfc_trans_pointer_assignment (expr1, expr2));
+      gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL);
+      gfc_free_expr (expr1);
+      gfc_free_expr (expr2);
+    }
   else if ((sym->attr.dimension || sym->attr.codimension) && !class_target
           && (sym->as->type == AS_DEFERRED || sym->assoc->variable))
     {
@@ -2077,8 +2123,9 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
          gfc_conv_class_to_class (&se, e, sym->ts, false, true, false, false);
          se.expr = build_fold_indirect_ref_loc (input_location, se.expr);
 
-         /* Set the offset.  */
          desc = gfc_class_data_get (se.expr);
+
+         /* Set the offset.  */
          offset = gfc_index_zero_node;
          for (n = 0; n < e->rank; n++)
            {
@@ -2088,9 +2135,11 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
                                     gfc_conv_descriptor_stride_get (desc, dim),
                                     gfc_conv_descriptor_lbound_get (desc, dim));
              offset = fold_build2_loc (input_location, MINUS_EXPR,
-                                       gfc_array_index_type,
-                                       offset, tmp);
+                                       gfc_array_index_type,
+                                       offset, tmp);
            }
+         gfc_conv_descriptor_offset_set (&se.pre, desc, offset);
+
          if (need_len_assign)
            {
              if (e->symtree
@@ -2118,7 +2167,6 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
              /* Length assignment done, prevent adding it again below.  */
              need_len_assign = false;
            }
-         gfc_conv_descriptor_offset_set (&se.pre, desc, offset);
        }
       else if (sym->ts.type == BT_CLASS && e->ts.type == BT_CLASS
               && CLASS_DATA (e)->attr.dimension)
index dfd5a99500e41b5860e6012ceb85ecdd58a087b5..7f690f3a75b3ddac95d88c8ad015f09cc6c3827a 100644 (file)
@@ -9,15 +9,15 @@ PROGRAM main
 
   ASSOCIATE ! { dg-error "Expected association list" }
 
-  ASSOCIATE () ! { dg-error "Expected association" }
+  ASSOCIATE () ! { dg-error "Expected associate name" }
 
   ASSOCIATE (a => 1) 5 ! { dg-error "Junk after ASSOCIATE" }
 
   ASSOCIATE (x =>) ! { dg-error "Invalid association target" }
 
-  ASSOCIATE (=> 5) ! { dg-error "Expected association" }
+  ASSOCIATE (=> 5) ! { dg-error "Expected associate name" }
 
-  ASSOCIATE (x => 5, ) ! { dg-error "Expected association" }
+  ASSOCIATE (x => 5, ) ! { dg-error "Expected associate name" }
 
   myname: ASSOCIATE (a => 1)
   END ASSOCIATE ! { dg-error "Expected block name of 'myname'" }
diff --git a/gcc/testsuite/gfortran.dg/f202y/f202y.exp b/gcc/testsuite/gfortran.dg/f202y/f202y.exp
new file mode 100644 (file)
index 0000000..5890af5
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (C) 2005-2024 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gfortran-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+global gfortran_test_path
+global gfortran_aux_module_flags
+set gfortran_test_path $srcdir/$subdir
+set gfortran_aux_module_flags "-std=f202y"
+proc dg-compile-aux-modules { args } {
+    global gfortran_test_path
+    global gfortran_aux_module_flags
+    if { [llength $args] != 2 } {
+       error "dg-compile-aux-modules: needs one argument"
+       return
+    }
+
+    set level [info level]
+    if { [info procs dg-save-unknown] != [list] } {
+       rename dg-save-unknown dg-save-unknown-level-$level
+    }
+
+    dg-test $gfortran_test_path/[lindex $args 1] "" $gfortran_aux_module_flags
+    # cleanup-modules is intentionally not invoked here.
+
+    if { [info procs dg-save-unknown-level-$level] != [list] } {
+       rename dg-save-unknown-level-$level dg-save-unknown
+    }
+}
+
+# Main loop.
+gfortran-dg-runtest [lsort \
+       [find $srcdir/$subdir *.\[fF\]{,90,95,03,08} ] ] "-std=f202y" ""
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_1.f90 b/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_1.f90
new file mode 100644 (file)
index 0000000..bca715e
--- /dev/null
@@ -0,0 +1,54 @@
+! { dg-do run }
+! { dg-options "-fcheck=bounds" }
+!
+! Test Reinhold Bader's F202y proposal (J3 DIN4) "Generic processing of assumed
+! rank objects". The present gfortran implementation includes pointer assignment
+! and ASSOCIATE, with rank remapping of the var or associate-name, and RESHAPE.
+! J3 document 24-136r1.txt, by Malcolm Cohen, considers further possibilities.
+!
+! Contributed by Paul Thomas  <pault@gcc.gnu.org>
+!
+   real :: x(2,2,2)
+   real, parameter :: xp(*) = [1,2,3,4,5,6,7,8]
+   x = reshape (xp, [2,2,2])
+   call my_sub (x)
+   if (any (reshape (x, [8]) .ne. xp(8:1:-1))) stop 1
+   call my_assumed_size_target (x)
+contains
+   subroutine my_sub (arg)
+     real, target, contiguous :: arg(..)
+     real, allocatable :: y(:)
+     real, pointer :: argp(:,:)
+     integer :: i
+
+     if (size (arg) .lt. 0) return
+
+     if (size (arg) .ne. 8) stop 10
+
+! Check reshape
+     y = reshape (arg, [size (arg)])
+     if (any (y .ne. xp)) stop 20
+
+! Check pointer assignment
+     argp(1:2,1: size(arg)/2) => arg
+     if (size (argp) .ne. size (x)) stop 30
+     if (any ((argp) .ne. reshape (x, [2, size (x)/2]))) stop 31
+
+! Check ASSOCIATE
+     i = size (arg)
+     associate (a(1:2,1:i/2) => arg)
+        if (any (a .ne. argp)) stop 40
+     end associate
+
+     associate (a(1:size(arg)) => arg)
+        if (any (a .ne. xp)) stop 41
+        a = a(8:1:-1)
+     end associate
+   end
+
+   subroutine my_assumed_size_target (arg)
+     real :: arg(2, 2, *)
+     call my_sub (arg)
+   end
+end
+! { dg-output "Fortran runtime warning: Assumed rank object arg is associated with an assumed size object" }
diff --git a/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_2.f90 b/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_2.f90
new file mode 100644 (file)
index 0000000..74ade73
--- /dev/null
@@ -0,0 +1,53 @@
+! { dg-do compile }
+! { dg-options "-std=f2023 -Wsurprising" }
+!
+! Test Reinhold Bader's F202y proposal (J3 DIN4) "Generic processing of assumed
+! rank objects". The present gfortran implementation includes pointer assignment
+! and ASSOCIATE, with rank remapping of the var or associate-name, and RESHAPE.
+! J3 document 24-136r1.txt, by Malcolm Cohen, considers further possibilities.
+!
+! Contributed by Paul Thomas  <pault@gcc.gnu.org>
+!
+   real :: x(2,2,2)
+   real, parameter :: xp(*) = [1,2,3,4,5,6,7,8]
+   x = reshape (xp, [2,2,2])
+   call my_sub (x)
+   if (any (reshape (x, [8]) .ne. xp(8:1:-1))) stop 1
+   call my_assumed_size_target (x)
+contains
+   subroutine my_sub (arg)
+     real, target, contiguous :: arg(..)
+     real, allocatable :: y(:)
+     real, pointer :: argp(:,:)
+     integer :: i
+
+     if (size (arg) .lt. 0) return
+
+     if (size (arg) .ne. 8) stop 10
+
+! Check reshape
+     y = reshape (arg, [size (arg)]) ! { dg-error "experimental F202y feature" }
+     if (any (y .ne. xp)) stop 20
+
+! Check pointer assignment
+     argp(1:2,1: size(arg)/2) => arg ! { dg-error "experimental F202y feature" }
+     if (size (argp) .ne. size (x)) stop 30
+     if (any ((argp) .ne. reshape (x, [2, size (x)/2]))) stop 31
+
+! Check ASSOCIATE
+     i = size (arg)
+     associate (a(1:2,1:i/2) => arg) ! { dg-error "experimental F202y feature" }
+        if (any (a .ne. argp)) stop 40
+     end associate
+
+     associate (a(1:size(arg)) => arg)  ! { dg-error "experimental F202y feature" }
+        if (any (a .ne. xp)) stop 41
+        a = a(8:1:-1)
+     end associate
+   end
+
+   subroutine my_assumed_size_target (arg)
+     real :: arg(2, 2, *)
+     call my_sub (arg)    ! { dg-warning "to an assumed-rank dummy" }
+   end
+end
diff --git a/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_3.f90 b/gcc/testsuite/gfortran.dg/f202y/generic_assumed_rank_3.f90
new file mode 100644 (file)
index 0000000..0fb5b02
--- /dev/null
@@ -0,0 +1,85 @@
+! { dg-do run }
+! { dg-options "-std=f202y -Wsurprising" }
+!
+! Test Reinhold Bader's F202y proposal "Generic processing of assumed rank objects".
+! Tests class assumed rank objects.
+!
+! Contributed by Paul Thomas  <pault@gcc.gnu.org>
+!
+   type :: t1
+     integer :: i
+   end type
+   type, extends(t1) :: t2
+     integer :: j
+   end type
+
+   class(t1), allocatable :: x(:,:)
+   type(t2), parameter :: xp(*) = [t2(t1(1),2),t2(t1(3),4),t2(t1(5),6),t2(t1(7),8)]
+   x = reshape (xp, [2,2])
+   call my_sub1 (x)
+   if (any (x(2:1:-1,2:1:-1)%i .ne. reshape (xp%i, [2,2]))) stop 1
+   call my_sub2 (x)
+   if (any (x(2:1:-1,2:1:-1)%i .ne. reshape (xp%i, [2,2]))) stop 2
+   deallocate (x)
+contains
+   subroutine my_sub1 (class_arg)
+      class(t1), contiguous, target :: class_arg(..)
+      class(t1), pointer :: cp(:)
+      integer :: cp_sz
+      integer :: lb(1)
+      integer :: ub(1)
+      integer :: slb = 2
+
+      cp_sz = size (class_arg)
+      cp(slb:slb+cp_sz-1) => class_arg
+      if (any (cp%i .ne. xp%i)) stop 3
+      if (size (cp) .ne. cp_sz) stop 4
+      if (ubound (cp, 1) .ne. slb+cp_sz-1) stop 5
+
+      associate (ca(slb:slb+cp_sz-1) => class_arg)
+         lb = lbound (ca)
+         ub = ubound (ca)
+         if (size (ca) .ne. cp_sz) stop 6
+         if (ubound (ca, 1) .ne. slb+cp_sz-1) stop 7
+         select type (ca)
+            type is (t2)
+               ca = ca(ub(1):lb(1):-1)
+            class default
+         end select
+      end associate
+   end
+
+   subroutine my_sub2 (class_arg)
+      class(*), contiguous, target :: class_arg(..)
+      class(*), pointer :: cp(:, :)
+      integer :: cp_sz
+      cp_sz = size (class_arg)
+      cp(1:cp_sz/2, 1:cp_sz/2) => class_arg
+      call check (cp, cp_sz)
+      associate (ca(2:3,1:2) => class_arg)
+         select type (ca)
+            type is (t2)
+               ca = ca(3:2:-1,2:1:-1)
+            class default
+         end select
+      end associate
+   end
+
+   subroutine check (arg, sz)
+      class(*), intent(inOUT) :: arg(:, :)
+      integer :: sz
+      integer :: lb(2)
+      integer :: ub(2)
+      lb = lbound(arg)
+      ub = ubound(arg)
+      select type (s => arg)
+         type is (t2)
+            s = s(ub(1):lb(1):-1,ub(2):lb(1):-1)
+            if (any (reshape (s(lb(1):ub(1),lb(2):ub(2))%j, [sz]) &
+                .ne. xp%j)) stop 8
+
+         class default
+            stop 9
+      end select
+   end
+end