[flang-commits] [flang] [flang][Semantics] Check defined-operator purity at the use site (PR #229976)
via flang-commits
flang-commits at lists.llvm.org
Mon Oct 19 21:06:24 PDT 2026
================
@@ -12,8 +12,210 @@ impure integer function func(x)
class(t), intent(in) :: x
func = 0
end
- pure integer function test
+ pure integer function pure_id(n)
+ integer, intent(in) :: n
+ pure_id = n
+ end
+ pure integer function test()
+ ! A direct call to a pure procedure is allowed.
+ test = pure_id(1)
!ERROR: Procedure 'func' referenced in pure subprogram 'test' must be pure too
test = .not. t()
end
end
+
+! F2023 C1595: a procedure referenced from a pure subprogram must be pure,
+! including references through defined operators (binary, unary, named,
+! and relational). The operator's generic is declared where its interface
+! block appears; the purity check must be anchored at the use site instead,
+! so each reference is diagnosed independently and the message points at
+! the call, not at the (possibly distant, possibly single) declaration.
+
+module pure_op_mod
+ implicit none
+ type, public :: vec_type
+ real :: x = 0.0, y = 0.0
+ end type vec_type
+
+ interface operator(+)
+ procedure impure_add ! impure
+ end interface operator(+)
+
+ interface operator(*)
+ procedure impure_scale ! impure
+ end interface operator(*)
+
+ interface operator(-)
+ procedure pure_sub ! binary, pure
+ procedure impure_neg ! unary, impure
+ end interface operator(-)
+
+ interface operator(==)
+ procedure impure_eq ! impure
+ end interface operator(==)
+
+ interface operator(.dot.)
+ procedure impure_dot ! impure
+ end interface operator(.dot.)
+
+ ! One generic, two specifics with different purity: only the specific
+ ! that overload resolution actually picks may be flagged.
+ interface operator(.scale.)
+ procedure pure_scale_int ! pure, (vec_type, integer)
+ procedure impure_scale_real ! impure, (vec_type, real)
+ end interface operator(.scale.)
+
+contains
+ function impure_add(a, b) result(r)
+ type(vec_type), intent(in) :: a, b
+ type(vec_type) :: r
+ r%x = a%x + b%x
+ r%y = a%y + b%y
+ end function impure_add
+
+ function impure_scale(s, v) result(r)
+ real, intent(in) :: s
+ type(vec_type), intent(in) :: v
+ type(vec_type) :: r
+ r%x = s * v%x
+ r%y = s * v%y
+ end function impure_scale
+
+ pure function pure_sub(a, b) result(r)
+ type(vec_type), intent(in) :: a, b
+ type(vec_type) :: r
+ r%x = a%x - b%x
+ r%y = a%y - b%y
+ end function pure_sub
+
+ function impure_neg(a) result(r)
+ type(vec_type), intent(in) :: a
+ type(vec_type) :: r
+ r%x = -a%x
+ r%y = -a%y
+ end function impure_neg
+
+ function impure_eq(a, b) result(same)
+ type(vec_type), intent(in) :: a, b
+ logical :: same
+ same = a%x == b%x .and. a%y == b%y
+ end function impure_eq
+
+ function impure_dot(a, b) result(d)
+ type(vec_type), intent(in) :: a, b
+ real :: d
+ d = a%x * b%x + a%y * b%y
+ end function impure_dot
+
+ pure function pure_scale_int(v, n) result(r)
+ type(vec_type), intent(in) :: v
+ integer, intent(in) :: n
+ type(vec_type) :: r
+ r%x = v%x * n
+ r%y = v%y * n
+ end function pure_scale_int
+
+ function impure_scale_real(v, s) result(r)
+ type(vec_type), intent(in) :: v
+ real, intent(in) :: s
+ type(vec_type) :: r
+ r%x = v%x * s
+ r%y = v%y * s
+ end function impure_scale_real
+
+ ! Pure, called from the ELEMENTAL and SIMPLE cases below so that the
+ ! only impurity they can trip over is the impure_add defined operator.
+ pure function pure_half(a) result(r)
+ type(vec_type), intent(in) :: a
+ type(vec_type) :: r
+ r%x = a%x * 0.5
+ r%y = a%y * 0.5
+ end function pure_half
+
+ ! ELEMENTAL is implicitly PURE unless declared IMPURE (F2023 15.7).
+ elemental function elemental_caller(p, q) result(r)
+ type(vec_type), intent(in) :: p, q
+ type(vec_type) :: r
+ ! A direct call to a pure procedure is allowed.
+ r = pure_half(p)
+ !ERROR: Procedure 'impure_add' (as OPERATOR(+)) referenced in pure subprogram 'elemental_caller' must be pure too
+ r = pure_half(p + q)
+ end function elemental_caller
+
+ ! SIMPLE implies PURE (F2023 15.8), and is stricter.
+ simple function simple_caller(p, q) result(r)
+ type(vec_type), intent(in) :: p, q
+ type(vec_type) :: r
+ ! A direct call to a pure procedure is allowed.
+ r = pure_half(p)
----------------
shivaramaarao wrote:
thank you. addressed this comment.
https://github.com/llvm/llvm-project/pull/229976
More information about the flang-commits
mailing list