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 +
