https://gcc.gnu.org/g:9861e3f70ee0909a814a0cfeb8cc7166d062cb20

commit r17-1666-g9861e3f70ee0909a814a0cfeb8cc7166d062cb20
Author: Thomas Koenig <[email protected]>
Date:   Sun Jun 14 08:43:00 2026 +0200

    Mark variables in references for variable definition context as used.
    
    Code like "a(i) = 42" would not mark i as used, leading to false
    positives for warnings with -Wunused-but-set-variable.  This is fixed
    in the attached patch.  It also removes some default arguments to
    make sure that the caller side provides correct information.
    
    gcc/fortran/ChangeLog:
    
            PR fortran/30438
            * gfortran.h (gfc_value_set_at): Remove default argument.
            (gfc_expr_set_at): Add prototype.
            * interface.cc (gfc_compare_actual_formal): Use gfc_expr_set_at.
            * intrinsic.cc (mark_args_as_used): Likewise.
            * io.cc (resolve_tag): Likewise.
            (gfc_resolve_dt): Likewise.
            (gfc_resolve_inquire): Likewise.
            * resolve.cc (resolve_transfer): Likewise.
            (mark_lhs_assignments_set): Likewise.
            * symbol.cc (gfc_lvalue_allocated_at): Add comment, fix formatting.
            (gfc_expr_set_at): New fuction.
    
    gcc/testsuite/ChangeLog:
    
            PR fortran/30438
            * gfortran.dg/warn_unused_but_set_variable_2.f90: New test.

Diff:
---
 gcc/fortran/gfortran.h                             |  7 +++---
 gcc/fortran/interface.cc                           |  2 +-
 gcc/fortran/intrinsic.cc                           |  2 +-
 gcc/fortran/io.cc                                  |  8 +++---
 gcc/fortran/resolve.cc                             |  6 ++---
 gcc/fortran/symbol.cc                              | 29 +++++++++++++++++++++-
 .../gfortran.dg/warn_unused_but_set_variable_2.f90 | 16 ++++++++++++
 7 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index ecbd4612bbea..907a42a87344 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -4005,9 +4005,8 @@ void gfc_warn_intrinsic_shadow (const gfc_symbol*, bool, 
bool);
 bool gfc_check_intrinsic_standard (const gfc_intrinsic_sym*, const char**,
                                      bool, locus);
 
-bool gfc_value_set_at (gfc_symbol *, locus *loc = NULL,
-                      enum value_set = VALUE_VARDEF);
-
+bool gfc_value_set_at (gfc_symbol *, locus *loc,
+                      enum value_set);
 bool gfc_lvalue_allocated_at (gfc_symbol *, locus *);
 void gfc_mark_lhs_as_used (gfc_expr *, locus *);
 
@@ -4015,6 +4014,8 @@ void gfc_value_used_expr (gfc_expr *, enum value_used);
 void gfc_value_set_and_used (gfc_expr *, locus *loc,
                             enum value_set, enum value_used);
 void gfc_used_in_allocate_expr (gfc_expr *, locus *loc);
+void gfc_expr_set_at (gfc_expr *, locus *loc, enum value_set);
+
 
 /* match.cc -- FIXME */
 void gfc_free_iterator (gfc_iterator *, int);
diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index 58308aec9da1..32152bd67772 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -4270,7 +4270,7 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, 
gfc_formal_arglist *formal,
              case INTENT_OUT:
                {
                  gfc_symbol *s = e->symtree->n.sym;
-                 gfc_value_set_at (s, &e->where, VALUE_INTENT_OUT);
+                 gfc_expr_set_at (e, &e->where, VALUE_INTENT_OUT);
 
                  /* INTENT(OUT) allocates variables as far as we know.  */
                  if (s->attr.allocatable)
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index df5400182333..12b6d30c71f5 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -5031,7 +5031,7 @@ mark_args_as_used (gfc_intrinsic_arg *f, 
gfc_actual_arglist *a)
              if (a->expr->expr_type == EXPR_VARIABLE)
                {
                  gfc_symbol *s = a->expr->symtree->n.sym;
-                 gfc_value_set_at (s, &a->expr->where, VALUE_INTENT_OUT);
+                 gfc_expr_set_at (a->expr, &a->expr->where, VALUE_INTENT_OUT);
                  if (s->attr.allocatable)
                    s->attr.allocated = 1;
                }
diff --git a/gcc/fortran/io.cc b/gcc/fortran/io.cc
index 85ff06fbda03..4720ea9a1f2e 100644
--- a/gcc/fortran/io.cc
+++ b/gcc/fortran/io.cc
@@ -1922,7 +1922,7 @@ resolve_tag (const io_tag *tag, gfc_expr *e)
       if (!gfc_check_vardef_context (e, false, false, false, context))
        return false;
 
-      gfc_value_set_at (e->symtree->n.sym, &e->where, VALUE_VARDEF);
+      gfc_expr_set_at (e, &e->where, VALUE_VARDEF);
     }
   else
     gfc_value_used_expr (e, VALUE_USED);
@@ -3410,7 +3410,7 @@ gfc_resolve_dt (gfc_code *dt_code, gfc_dt *dt, locus *loc)
                                        _("internal unit in WRITE")))
            return false;
 
-         gfc_value_set_at (e->symtree->n.sym, &e->where);
+         gfc_expr_set_at (e, &e->where, VALUE_VARDEF);
        }
     }
 
@@ -3455,7 +3455,7 @@ gfc_resolve_dt (gfc_code *dt_code, gfc_dt *dt, locus *loc)
                             dt->namelist->name, loc, n->sym->name);
                  return false;
                }
-             gfc_value_set_at (n->sym, NULL);
+             gfc_value_set_at (n->sym, NULL, VALUE_VARDEF);
            }
 
          t = dtio_procs_present (n->sym, k);
@@ -4793,7 +4793,7 @@ gfc_resolve_inquire (gfc_inquire *inquire)
       if (gfc_check_vardef_context ((expr), false, false, false, \
                                    context) == false) \
        return false; \
-      gfc_value_set_at (expr->symtree->n.sym, &expr->where); \
+      gfc_expr_set_at (expr, &expr->where, VALUE_VARDEF);      \
     }
   INQUIRE_RESOLVE_TAG (&tag_iomsg, inquire->iomsg);
   INQUIRE_RESOLVE_TAG (&tag_iostat, inquire->iostat);
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 57561e8686fc..d479b6a80e51 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -9753,7 +9753,7 @@ success:
   gfc_used_in_allocate_expr (e, &e->where);
 
   if (code->expr3)
-    gfc_value_set_at (e->symtree->n.sym, &code->expr3->where);
+    gfc_value_set_at (e->symtree->n.sym, &code->expr3->where, VALUE_VARDEF);
 
   return true;
 
@@ -11784,7 +11784,7 @@ resolve_transfer (gfc_code *code)
                                     _("item in READ")))
        return;
 
-      gfc_value_set_at (exp->symtree->n.sym, &exp->where, VALUE_READ);
+      gfc_expr_set_at (exp, &exp->where, VALUE_READ);
     }
 
   const gfc_typespec *ts = exp->expr_type == EXPR_STRUCTURE
@@ -20588,7 +20588,7 @@ mark_lhs_assignments_set (gfc_code *code)
 
          gcc_fallthrough();
        case EXEC_POINTER_ASSIGN:
-         gfc_value_set_at (lvalue->symtree->n.sym, &rvalue->where);
+         gfc_expr_set_at (lvalue, &rvalue->where, VALUE_VARDEF);
        default:
          break;
        }
diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index 7d08edd0afb4..72ffa1919549 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -5915,8 +5915,10 @@ gfc_used_in_allocate_expr (gfc_expr *expr, locus *loc)
     sym->extra_loc = *loc;
 }
 
+/* Mark a symbol to allocated.  */
 
-bool gfc_lvalue_allocated_at (gfc_symbol *sym, locus *loc)
+bool
+gfc_lvalue_allocated_at (gfc_symbol *sym, locus *loc)
 {
   if (sym->other_loc.nextc == 0)
     sym->other_loc = *loc;
@@ -5924,3 +5926,28 @@ bool gfc_lvalue_allocated_at (gfc_symbol *sym, locus 
*loc)
   sym->attr.allocated = 1;
   return true;
 }
+
+/* Mark the variable of an expression in a vardef context as
+   set and mark everything in the references as used.  */
+
+void
+gfc_expr_set_at (gfc_expr *expr, locus *loc, enum value_set how_set)
+{
+  enum value_used prev_used;
+  gfc_symbol *sym;
+  locus prev_loc;
+
+  if (!expr)
+    return;
+
+  if (expr->expr_type != EXPR_VARIABLE)
+    return;
+
+  sym = expr->symtree->n.sym;
+  gfc_value_set_at (sym, loc, how_set);
+  prev_used = sym->attr.value_used;
+  prev_loc = sym->other_loc;
+  gfc_value_used_expr (expr, VALUE_USED);
+  sym->other_loc = prev_loc;
+  sym->attr.value_used = prev_used;
+}
diff --git a/gcc/testsuite/gfortran.dg/warn_unused_but_set_variable_2.f90 
b/gcc/testsuite/gfortran.dg/warn_unused_but_set_variable_2.f90
new file mode 100644
index 000000000000..19e008673ccc
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/warn_unused_but_set_variable_2.f90
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-Wunused-but-set-variable" }
+program main
+  integer :: i,j, k
+  real, dimension(100) :: a
+  integer, dimension(50) :: ios
+  i = 42
+  j = 42
+  read (*,*) a(i)
+  print *, a(j)
+
+  k = 42
+  read (*,*,iostat=ios(k)) a(10)
+  print *,ios(42)
+end program main
+

Reply via email to