gfortran fails to compile ASSOCIATE constructs whose selector is a type-bound user-defined operator (UDO) expression. Three related cases are affected: 1. A direct type-bound UDO as the selector (associate (g => .grad. s)). 2. An inherited UDO defined on a parent type (associate (q => .sq. s)). 3. Nested UDO expressions (associate (r => .div. (.grad. s))). In case 1 gfortran produces an ICE ("Syntax error in expression") inside the ASSOCIATE body because the associate variable is left without a type. Cases 2 and 3 produce similar failures. Intel Fortran and NAG Fortran accept all three cases. module m implicit none type :: scalar_t real :: val contains generic :: operator(.grad.) => do_grad procedure, private :: do_grad generic :: operator(.sq.) => do_sq procedure, private :: do_sq generic :: get => get_val procedure :: get_val end type type, extends(scalar_t) :: vector_t contains generic :: operator(.div.) => do_div procedure, private :: do_div end type contains pure function do_grad (self) result (r) class(scalar_t), intent(in) :: self type(vector_t) :: r r%val = self%val * 2.0 end function pure function do_sq (self) result (r) class(scalar_t), intent(in) :: self type(scalar_t) :: r r%val = self%val * self%val end function pure function do_div (self) result (r) class(vector_t), intent(in) :: self type(scalar_t) :: r r%val = self%val / 2.0 end function pure function get_val (self) result (r) class(scalar_t), intent(in) :: self real :: r r = self%val end function end module m program p use m implicit none type(scalar_t) :: s s%val = 3.0 associate (g => .grad. s) ! case 1 if (abs (g%val - 6.0) > 1.0e-6) stop 1 end associate associate (q => .sq. s) ! case 2 if (abs (q%val - 9.0) > 1.0e-6) stop 2 end associate associate (r => .div. (.grad. s)) ! case 3 if (abs (r%val - 3.0) > 1.0e-6) stop 3 end associate end program p $ gfortran associate.f90 gfortran ICEs or rejects the code. The program should compile and run cleanly.
The master branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:8c57a6b7959dcf16ed5321cd5214f66e7e6ad4d7 commit r17-1357-g8c57a6b7959dcf16ed5321cd5214f66e7e6ad4d7 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Wed May 27 15:10:07 2026 -0700 fortran: ICE or wrong-code for ASSOCIATE selector that is a type-bound user-defined operator Three related bugs prevented ASSOCIATE selectors that are type-bound user-defined operator expressions from compiling correctly. Bug 1 (class.cc): find_typebound_proc_uop returned NULL immediately when the derived type has no f2k_derived namespace, bypassing the parent-type inheritance walk. This caused inherited UDOs to be silently not found. Fix: set root = NULL and let the loop reach the parent type instead. Bug 2 (resolve.cc): resolve_typebound_procedures called resolve_symbol on the parent type only after an early return that fires when the derived type has no direct type-bound bindings. This left parent-type bindings unresolved when searched via gfc_find_typebound_user_op. Fix: move resolve_symbol(super_type) before the early return. Bug 3 (match.cc): match_association_list did not handle ASSOCIATE selectors of the form .uop. expr or the nested case .uop2. (.uop1. expr). When the selector's type was BT_UNKNOWN at parse time the name of the associate variable was left untyped, producing a "Syntax error in expression" ICE in the body of the ASSOCIATE construct. Fix: add three helpers before match_association_list: - resolve_assoc_operand: attempts gfc_resolve_expr on EXPR_FUNCTION operands and falls back to gfc_find_dt_in_generic for constructor calls whose argument types are not yet known. - infer_typebound_uop_type: reads the return type of a type-bound UDO directly from specific_st->n.tb->u.specific->n.sym without calling gfc_resolve_symbol, avoiding a resolve_symbol_called race condition. - extend_assoc_op: walks the expression tree bottom-up, propagating types through INTRINSIC_PARENTHESES wrappers before calling the two helpers above on each INTRINSIC_USER node. When the selector is an INTRINSIC_USER EXPR_OP with BT_UNKNOWN type, call extend_assoc_op on the operands, then gfc_extend_expr (errors suppressed). Accept the result when gfc_extend_expr returns MATCH_YES or when it returns MATCH_ERROR but has already converted the node to EXPR_COMPCALL with a known type (the full resolution pass finishes it). Assisted by: Claude Sonnet 4.6 PR fortran/125528 gcc/fortran/ChangeLog: PR fortran/125528 * class.cc (find_typebound_proc_uop): Set root = NULL instead of returning NULL when derived type lacks f2k_derived, so parent-type type-bound procedures and operators are still found via inheritance. * match.cc (resolve_assoc_operand): New helper. (infer_typebound_uop_type): New helper. (extend_assoc_op): New helper. (match_association_list): Handle ASSOCIATE selectors that are type-bound user-defined operator expressions, including nested cases. * resolve.cc (resolve_typebound_procedures): Move resolve_symbol call for the parent type before the early return so inherited type-bound bindings are resolved even when the child type has none of its own. gcc/testsuite/ChangeLog: PR fortran/125528 * gfortran.dg/associate_80.f90: New test.
The releases/gcc-16 branch has been updated by Jerry DeLisle <jvdelisle@gcc.gnu.org>: https://gcc.gnu.org/g:dfe38eb88b4e69be691e3495038d292edff77f36 commit r16-9107-gdfe38eb88b4e69be691e3495038d292edff77f36 Author: Jerry DeLisle <jvdelisle@gcc.gnu.org> Date: Wed May 27 15:10:07 2026 -0700 fortran: ICE or wrong-code for ASSOCIATE selector that is a type-bound user-defined operator Three related bugs prevented ASSOCIATE selectors that are type-bound user-defined operator expressions from compiling correctly. Bug 1 (class.cc): find_typebound_proc_uop returned NULL immediately when the derived type has no f2k_derived namespace, bypassing the parent-type inheritance walk. This caused inherited UDOs to be silently not found. Fix: set root = NULL and let the loop reach the parent type instead. Bug 2 (resolve.cc): resolve_typebound_procedures called resolve_symbol on the parent type only after an early return that fires when the derived type has no direct type-bound bindings. This left parent-type bindings unresolved when searched via gfc_find_typebound_user_op. Fix: move resolve_symbol(super_type) before the early return. Bug 3 (match.cc): match_association_list did not handle ASSOCIATE selectors of the form .uop. expr or the nested case .uop2. (.uop1. expr). When the selector's type was BT_UNKNOWN at parse time the name of the associate variable was left untyped, producing a "Syntax error in expression" ICE in the body of the ASSOCIATE construct. Add three helpers before match_association_list: - resolve_assoc_operand: attempts gfc_resolve_expr on EXPR_FUNCTION operands and falls back to gfc_find_dt_in_generic for constructor calls whose argument types are not yet known. - infer_typebound_uop_type: reads the return type of a type-bound UDO directly from specific_st->n.tb->u.specific->n.sym without calling gfc_resolve_symbol, avoiding a resolve_symbol_called race condition. - extend_assoc_op: walks the expression tree bottom-up, propagating types through INTRINSIC_PARENTHESES wrappers before calling the two helpers above on each INTRINSIC_USER node. When the selector is an INTRINSIC_USER EXPR_OP with BT_UNKNOWN type, call extend_assoc_op on the operands, then gfc_extend_expr (errors suppressed). Accept the result when gfc_extend_expr returns MATCH_YES or when it returns MATCH_ERROR but has already converted the node to EXPR_COMPCALL with a known type (the full resolution pass finishes it). Assisted-by: Claude Sonnet 4.6 PR fortran/125528 gcc/fortran/ChangeLog: * class.cc (find_typebound_proc_uop): Set root = NULL instead of returning NULL when derived type lacks f2k_derived, so parent-type type-bound procedures and operators are still found via inheritance. * match.cc (resolve_assoc_operand): New helper. (infer_typebound_uop_type): New helper. (extend_assoc_op): New helper. (match_association_list): Handle ASSOCIATE selectors that are type-bound user-defined operator expressions, including nested cases. * resolve.cc (resolve_typebound_procedures): Move resolve_symbol call for the parent type before the early return so inherited type-bound bindings are resolved even when the child type has none of its own. gcc/testsuite/ChangeLog: * gfortran.dg/associate_80.f90: New test. (cherry picked from commit 6340639219bb2d1816c94e5de76ec3642453bcb2)
Fixed and closing