[flang-commits] [flang] flang] Check defined-operator purity at the use site (PR #229976)

via flang-commits flang-commits at lists.llvm.org
Wed Oct 7 20:04:15 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: shivaramaarao

<details>
<summary>Changes</summary>

AnalyzeDefinedOp passed the generic's declaration to MakeFunctionRef, so C1595 ran in the module instead of in the pure subprogram that used the operator. This is fixed by using the current expression location as the call site.

Added a semantics test that an impure defined operator is rejected inside a pure function and accepted outside one.

Fixes issue #<!-- -->222888

Assisted by Cursor to get the root cause of issue

---
Full diff: https://github.com/llvm/llvm-project/pull/229976.diff


2 Files Affected:

- (modified) flang/lib/Semantics/expression.cpp (+7-1) 
- (added) flang/test/Semantics/pure-defined-op.f90 (+74) 


``````````diff
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 91e98d5c8018c..f94e3c026ee2f 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -4369,11 +4369,17 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Concat &x) {
 // Otherwise report the error in messages.
 MaybeExpr ExpressionAnalyzer::AnalyzeDefinedOp(const parser::Name &name,
     ActualArguments &&actuals, const Symbol *&symbol) {
+  // Reference checks such as F2018 C1595 (a procedure referenced in a
+  // pure subprogram must be pure) must be applied at the use site
+  parser::CharBlock callSite{GetContextualMessages().at()};
+  if (callSite.empty()) {
+    callSite = name.source;
+  }
   if (auto callee{GetCalleeAndArguments(name, std::move(actuals))}) {
     auto &proc{std::get<evaluate::ProcedureDesignator>(callee->u)};
     symbol = proc.GetSymbol();
     return MakeFunctionRef(
-        name.source, std::move(proc), std::move(callee->arguments));
+        callSite, std::move(proc), std::move(callee->arguments));
   } else {
     return std::nullopt;
   }
diff --git a/flang/test/Semantics/pure-defined-op.f90 b/flang/test/Semantics/pure-defined-op.f90
new file mode 100644
index 0000000000000..ae80155950d05
--- /dev/null
+++ b/flang/test/Semantics/pure-defined-op.f90
@@ -0,0 +1,74 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! F2018 C1595: a procedure referenced from a pure subprogram must be pure,
+! including references through defined operators. The operator's generic
+! is declared in the module; the check must use the use site.
+
+module pure_op_mod
+  implicit none
+  type, public :: pv_type
+    real :: x = 0.0, y = 0.0
+  end type pv_type
+
+  interface operator(+)
+    module function pv_add(a, b) result(r)
+      type(pv_type), intent(in) :: a, b
+      type(pv_type) :: r
+    end function pv_add
+  end interface operator(+)
+
+  interface operator(*)
+    module function pv_scale(s, v) result(r)
+      real, intent(in) :: s
+      type(pv_type), intent(in) :: v
+      type(pv_type) :: r
+    end function pv_scale
+  end interface operator(*)
+
+  interface operator(-)
+    pure module function pv_sub(a, b) result(r)
+      type(pv_type), intent(in) :: a, b
+      type(pv_type) :: r
+    end function pv_sub
+  end interface operator(-)
+end module pure_op_mod
+
+submodule (pure_op_mod) pure_op_smod
+  implicit none
+contains
+  module procedure pv_add
+    r%x = a%x + b%x
+    r%y = a%y + b%y
+  end procedure pv_add
+
+  module procedure pv_scale
+    r%x = s * v%x
+    r%y = s * v%y
+  end procedure pv_scale
+
+  module procedure pv_sub
+    r%x = a%x - b%x
+    r%y = a%y - b%y
+  end procedure pv_sub
+end submodule pure_op_smod
+
+program main
+  use pure_op_mod
+  implicit none
+  type(pv_type) :: a, b, m
+  a = pv_type(1.0, 2.0)
+  b = pv_type(3.0, 4.0)
+  ! Impure defined operators are fine outside a pure subprogram.
+  m = 0.5 * (a + b)
+  m = a - b
+  m = midpoint(a, b)
+contains
+  pure function midpoint(p, q) result(r)
+    type(pv_type), intent(in) :: p, q
+    type(pv_type) :: r
+    ! A pure defined operator may be referenced.
+    r = p - q
+    !ERROR: Procedure 'pv_add' referenced in pure subprogram 'midpoint' must be pure too
+    !ERROR: Procedure 'pv_scale' referenced in pure subprogram 'midpoint' must be pure too
+    r = 0.5 * (p + q)
+  end function midpoint
+end program main

``````````

</details>


https://github.com/llvm/llvm-project/pull/229976


More information about the flang-commits mailing list