https://gcc.gnu.org/g:7e72a078ae71594f6f34d406a80b47ca90cf876e

commit 7e72a078ae71594f6f34d406a80b47ca90cf876e
Author: Mikael Morin <mik...@gcc.gnu.org>
Date:   Wed Jul 9 09:40:32 2025 +0200

    fortran: Amend descriptor bounds init if unallocated
    
    Always generate the conditional initialization of unallocated variables
    regardless of the basic variable allocation tracking done in the
    frontend and with an additional always false condition.
    
    The scalarizer used to always evaluate array bounds, including in the
    case of unallocated arrays on the left hand side of an assignment.  This
    was (correctly) causing uninitialized warnings, even if the
    uninitialized values were in the end discarded.
    
    Since the fix for PR fortran/108889, an initialization of the descriptor
    bounds is added to silent the uninitialized warnings, conditional on the
    array being unallocated.  This initialization is not useful in the
    execution of the program, and it is removed if the compiler can prove
    that the variable is unallocated (in the case of a local variable for
    example).  Unfortunately, the compiler is not always able to prove it
    and the useless initialization may remain in the final code.
    Moreover, the generated code that was causing the evaluation of
    uninitialized variables has ben changed to avoid them, so we can try to
    remove or revisit that unallocated variable bounds initialization tweak.
    
    Unfortunately, just removing the extra initialization restores the
    warnings at -O0, as there is no dead code removal at that optimization
    level.  Instead, this change keeps the initialization and modifies its
    guarding condition with an extra always false variable, so that if
    optimizations are enabled the whole initialization block is removed, and
    if they are disabled it remains and is sufficient to prevent the
    warning.
    
    The new variable requires the code generation to be done earlier in the
    function so that the variable declaration and usage are in the same
    scope.
    
    As the modified condition guarantees the removal of the block with
    optimizations, we can emit it more broadly and remove the basic
    allocation tracking that was done in the frontend to limit its emission.
    
    gcc/fortran/ChangeLog:
    
            * gfortran.h (gfc_symbol): Remove field allocated_in_scope.
            * trans-array.cc (gfc_array_allocate): Don't set it.
            (gfc_alloc_allocatable_for_assignment): Likewise.
            Generate the unallocated descriptor bounds initialisation
            before the opening of the reallocation code block.  Create a
            variable and use it as additional condition to the unallocated
            descriptor bounds initialisation.

Diff:
---
 gcc/fortran/gfortran.h     |  4 --
 gcc/fortran/trans-array.cc | 91 ++++++++++++++++++++++++----------------------
 2 files changed, 48 insertions(+), 47 deletions(-)

diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 6848bd1762d3..69367e638c5b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2028,10 +2028,6 @@ typedef struct gfc_symbol
   /* Set if this should be passed by value, but is not a VALUE argument
      according to the Fortran standard.  */
   unsigned pass_as_value:1;
-  /* Set if an allocatable array variable has been allocated in the current
-     scope. Used in the suppression of uninitialized warnings in reallocation
-     on assignment.  */
-  unsigned allocated_in_scope:1;
   /* Set if an external dummy argument is called with different argument lists.
      This is legal in Fortran, but can cause problems with autogenerated
      C prototypes for C23.  */
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 7b83d3fab8d7..52888c1e1f1b 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -6800,8 +6800,6 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree 
status, tree errmsg,
   else
       gfc_add_expr_to_block (&se->pre, set_descriptor);
 
-  expr->symtree->n.sym->allocated_in_scope = 1;
-
   return true;
 }
 
@@ -11495,14 +11493,60 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
       && !expr2->value.function.isym)
     expr2->ts.u.cl->backend_decl = rss->info->string_length;
 
-  gfc_start_block (&fblock);
-
   /* Since the lhs is allocatable, this must be a descriptor type.
      Get the data and array size.  */
   desc = linfo->descriptor;
   gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)));
   array1 = gfc_conv_descriptor_data_get (desc);
 
+  /* If the data is null, set the descriptor bounds and offset.  This 
suppresses
+     the maybe used uninitialized warning.  Note that the always false variable
+     prevents this block from from ever being executed.  The whole block should
+     be removed by optimizations.  Component references are not subject to the
+     warnings, so we don't uselessly complicate the generated code for them.  
*/
+  for (ref = expr1->ref; ref; ref = ref->next)
+    if (ref->type == REF_COMPONENT)
+      break;
+
+  if (!ref)
+    {
+      stmtblock_t unalloc_init_block;
+      gfc_init_block (&unalloc_init_block);
+      tree guard = gfc_create_var (logical_type_node, 
"unallocated_init_guard");
+      gfc_add_modify (&unalloc_init_block, guard, logical_false_node);
+
+      gfc_start_block (&loop_pre_block);
+      for (n = 0; n < expr1->rank; n++)
+       {
+         gfc_conv_descriptor_lbound_set (&loop_pre_block, desc,
+                                         gfc_rank_cst[n],
+                                         gfc_index_one_node);
+         gfc_conv_descriptor_ubound_set (&loop_pre_block, desc,
+                                         gfc_rank_cst[n],
+                                         gfc_index_zero_node);
+         gfc_conv_descriptor_stride_set (&loop_pre_block, desc,
+                                         gfc_rank_cst[n],
+                                         gfc_index_zero_node);
+       }
+
+      tmp = gfc_conv_descriptor_offset (desc);
+      gfc_add_modify (&loop_pre_block, tmp, gfc_index_zero_node);
+
+      tmp = fold_build2_loc (input_location, EQ_EXPR,
+                            logical_type_node, array1,
+                            build_int_cst (TREE_TYPE (array1), 0));
+      tmp = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR,
+                            logical_type_node, tmp, guard);
+      tmp = build3_v (COND_EXPR, tmp,
+                     gfc_finish_block (&loop_pre_block),
+                     build_empty_stmt (input_location));
+      gfc_prepend_expr_to_block (&loop->pre, tmp);
+      gfc_prepend_expr_to_block (&loop->pre,
+                                gfc_finish_block (&unalloc_init_block));
+    }
+
+  gfc_start_block (&fblock);
+
   if (expr2)
     desc2 = rss->info->data.array.descriptor;
   else
@@ -11615,45 +11659,6 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo 
*loop,
                         array1, build_int_cst (TREE_TYPE (array1), 0));
   cond_null= gfc_evaluate_now (cond_null, &fblock);
 
-  /* If the data is null, set the descriptor bounds and offset. This suppresses
-     the maybe used uninitialized warning and forces the use of malloc because
-     the size is zero in all dimensions. Note that this block is only executed
-     if the lhs is unallocated and is only applied once in any namespace.
-     Component references are not subject to the warnings.  */
-  for (ref = expr1->ref; ref; ref = ref->next)
-    if (ref->type == REF_COMPONENT)
-      break;
-
-  if (!expr1->symtree->n.sym->allocated_in_scope && !ref)
-    {
-      gfc_start_block (&loop_pre_block);
-      for (n = 0; n < expr1->rank; n++)
-       {
-         gfc_conv_descriptor_lbound_set (&loop_pre_block, desc,
-                                         gfc_rank_cst[n],
-                                         gfc_index_one_node);
-         gfc_conv_descriptor_ubound_set (&loop_pre_block, desc,
-                                         gfc_rank_cst[n],
-                                         gfc_index_zero_node);
-         gfc_conv_descriptor_stride_set (&loop_pre_block, desc,
-                                         gfc_rank_cst[n],
-                                         gfc_index_zero_node);
-       }
-
-      tmp = gfc_conv_descriptor_offset (desc);
-      gfc_add_modify (&loop_pre_block, tmp, gfc_index_zero_node);
-
-      tmp = fold_build2_loc (input_location, EQ_EXPR,
-                            logical_type_node, array1,
-                            build_int_cst (TREE_TYPE (array1), 0));
-      tmp = build3_v (COND_EXPR, tmp,
-                     gfc_finish_block (&loop_pre_block),
-                     build_empty_stmt (input_location));
-      gfc_prepend_expr_to_block (&loop->pre, tmp);
-
-      expr1->symtree->n.sym->allocated_in_scope = 1;
-    }
-
   tmp = build3_v (COND_EXPR, cond_null,
                  build1_v (GOTO_EXPR, jump_label1),
                  build_empty_stmt (input_location));

Reply via email to