[flang-commits] [flang] 64bcef5 - [flang] Classify intrinsic functions as SIMPLE (#223160)

via flang-commits flang-commits at lists.llvm.org
Fri Oct 9 10:48:59 PDT 2026


Author: Šárka Holendová
Date: 2026-10-09T13:48:53-04:00
New Revision: 64bcef58a8e16302a9c7b3d14224255c8e599e97

URL: https://github.com/llvm/llvm-project/commit/64bcef58a8e16302a9c7b3d14224255c8e599e97
DIFF: https://github.com/llvm/llvm-project/commit/64bcef58a8e16302a9c7b3d14224255c8e599e97.diff

LOG: [flang] Classify intrinsic functions as SIMPLE (#223160)

Classify standard intrinsic functions as `SIMPLE` per Fortran 2023 16.1(2).

This change also:
- Classifies extensions as `SIMPLE` where applicable
- Documents the `SIMPLE` and non-`SIMPLE` classifications of extensions
in Extensions.md
- Updates procedure-interface tests affected by the new `SIMPLE`
classification
- Updates F202X.md to reflect the current `SIMPLE` implementation status

Part of the `SIMPLE` procedure support tracked in #221457.

Added: 
    flang/test/Semantics/null-mold-pure-simple.f90
    flang/test/Semantics/simple-intrinsic-functions.f90

Modified: 
    flang/docs/Extensions.md
    flang/docs/F202X.md
    flang/docs/ReleaseNotes.md
    flang/lib/Evaluate/intrinsics.cpp
    flang/test/Semantics/intrinsics03.f90
    flang/test/Semantics/procinterface01.f90
    flang/test/Semantics/procinterface02.f90

Removed: 
    


################################################################################
diff  --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 2de84d3d628b83..b61ee16c64d322 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -587,6 +587,16 @@ end program
   rather than an allocatable, it is interpreted as `ASSOCIATED(p)` with a
   stern warning.
 
+### `SIMPLE` classification of extensions
+
+The following extensions are `SIMPLE`: `IARGC`, `INT2`, `INT8`, `INT_PTR_KIND`, `ISNAN`,
+`IZEXT`, `JZEXT`, `LNBLNK`, `LOC`, `SELECTED_UNSIGNED_KIND`, `SIZEOF`, `UINT`, `UMASKL`,
+and `UMASKR`. All specific intrinsic extensions are also `SIMPLE`.
+
+The following extensions are not classified as `SIMPLE`: `CHDIR`, `DSECNDS`, `ETIME`,
+`FSEEK`, `FTELL`, `GETCWD`, `GETGID`, `GETPID`, `GETUID`, `HOSTNM`, `IRAND`, `MALLOC`,
+`PUTENV`, `RAND`, `RENAME`, `RTC`, `SECNDS`, `SECOND`, `SYSTEM`, `TIME`, `TIMEF`, and `UNLINK`.
+
 ### Extensions supported when enabled by options
 
 * C-style backslash escape sequences in quoted CHARACTER literals

diff  --git a/flang/docs/F202X.md b/flang/docs/F202X.md
index 7d0cf26dbaa2c1..67452fa9ae6689 100644
--- a/flang/docs/F202X.md
+++ b/flang/docs/F202X.md
@@ -175,8 +175,14 @@ This makes `SIMPLE` a lower-priority feature.
 - `PURE` procedures do not satisfy `SIMPLE` requirements
 - `SIMPLE`/`IMPURE` conflicts are diagnosed
 - Use-associated `SIMPLE` procedures are correctly recognized
-- Additional `SIMPLE` semantic constraints remain to be implemented
-- Intrinsic procedures are not yet marked as `SIMPLE` (planned as follow-up work)
+- Additional `SIMPLE` semantic constraints remain to be implemented (see #221457)
+- F2023 16.1 p2: All standard intrinsic functions are classified as `SIMPLE`
+- F2023 16.1 p5: `MVBITS`, `SPLIT`, and both forms of `TOKENIZE` are classified
+  as `SIMPLE` intrinsic subroutines
+- F2023 16.1 p5: Conditional `SIMPLE` classification of `MOVE_ALLOC` is not yet
+  implemented (planned as follow-up work)
+- Intrinsic module procedures are not yet classified as `SIMPLE`
+- Lowering does not yet propagate the `SIMPLE` attribute to FIR procedure attributes (see #222360)
 
 #### Conditional expressions and actual arguments
 

diff  --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index 7da44606aa37fa..609ca499da3965 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -161,6 +161,13 @@ page](https://llvm.org/releases/).
 ## Windows Support
 
 ## Fortran Language Changes in Flang
+- Standard intrinsic functions are now classified as `SIMPLE` (F2023 16.1 p2).
+  A procedure pointer or dummy procedure whose interface is an intrinsic
+  function, such as `procedure(sqrt)`, can no longer be associated with a
+  procedure that is `PURE` but not `SIMPLE` (F2023 10.2.2.4 p3,
+  F2023 15.5.2.10 p1). Declare the target `SIMPLE` if it satisfies the
+  `SIMPLE` constraints, or give the pointer or dummy an explicit `PURE`
+  interface.
 
 ## Build System Changes
 

diff  --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 70561b6caaf232..dda75d56fa615b 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -19,6 +19,7 @@
 #include "flang/Semantics/scope.h"
 #include "flang/Semantics/tools.h"
 #include "flang/Support/Fortran.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <climits>
@@ -2889,9 +2890,19 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
             name, characteristics::Procedure{std::move(dummyArgs), attrs}},
         std::move(rearranged)};
   } else {
-    // TODO: Mark intrinsic functions that are SIMPLE per F2023
-    if (intrinsicClass != IntrinsicClass::impureFunction /* RAND and IRAND */)
+    if (intrinsicClass != IntrinsicClass::impureFunction /* RAND and IRAND */) {
       attrs.set(characteristics::Procedure::Attr::Pure);
+      // F2023 16.1: standard intrinsic functions are SIMPLE. Extensions that
+      // are not SIMPLE: they have side effects, or their result varies with
+      // external state. See docs/Extensions.md.
+      static const llvm::StringSet<> notSimpleExtensionFunctions{"chdir",
+          "dsecnds", "etime", "fseek", "ftell", "getcwd", "getgid", "getpid",
+          "getuid", "hostnm", "irand", "malloc", "putenv", "rand", "rename",
+          "rtc", "secnds", "second", "system", "time", "timef", "unlink"};
+      if (!notSimpleExtensionFunctions.contains(name)) {
+        attrs.set(characteristics::Procedure::Attr::Simple);
+      }
+    }
     characteristics::TypeAndShape typeAndShape{resultType.value(), resultRank};
     characteristics::FunctionResult funcResult{std::move(typeAndShape)};
     characteristics::Procedure chars{
@@ -3200,6 +3211,8 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
           attrs.set(isAllocatableMold
                   ? characteristics::Procedure::Attr::NullAllocatable
                   : characteristics::Procedure::Attr::NullPointer);
+          attrs.set(characteristics::Procedure::Attr::Pure);
+          attrs.set(characteristics::Procedure::Attr::Simple);
           characteristics::Procedure chars{
               std::move(*fResult), std::move(args), attrs};
           return SpecificCall{SpecificIntrinsic{"null"s, std::move(chars)},
@@ -3215,6 +3228,7 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
   characteristics::Procedure::Attrs attrs;
   attrs.set(characteristics::Procedure::Attr::NullPointer);
   attrs.set(characteristics::Procedure::Attr::Pure);
+  attrs.set(characteristics::Procedure::Attr::Simple);
   arguments.clear();
   return SpecificCall{
       SpecificIntrinsic{"null"s,
@@ -4424,7 +4438,9 @@ IntrinsicProcTable::Implementation::IsSpecificIntrinsicFunction(
           std::string{specific.dummy[j].keyword}, std::move(dummy));
     }
     characteristics::Procedure::Attrs attrs;
-    attrs.set(characteristics::Procedure::Attr::Pure)
+    // F2023 16.1: specific intrinsic functions are SIMPLE
+    attrs.set(characteristics::Procedure::Attr::Simple)
+        .set(characteristics::Procedure::Attr::Pure)
         .set(characteristics::Procedure::Attr::Elemental);
     characteristics::Procedure chars{
         std::move(fResult), std::move(args), attrs};

diff  --git a/flang/test/Semantics/intrinsics03.f90 b/flang/test/Semantics/intrinsics03.f90
index 1a4269868a3d49..801d44a0e97ec6 100644
--- a/flang/test/Semantics/intrinsics03.f90
+++ b/flang/test/Semantics/intrinsics03.f90
@@ -3,16 +3,16 @@
 
 program test
   interface
-    pure integer function index1(string, substring)
+    simple integer function index1(string, substring)
       character(*), intent(in) :: string, substring ! ok
     end
-    pure integer function index2(x1, x2)
+    simple integer function index2(x1, x2)
       character(*), intent(in) :: x1, x2 ! ok
     end
-    pure integer function index3(string, substring)
+    simple integer function index3(string, substring)
       character, intent(in) :: string, substring ! not assumed length
     end
-    pure integer function index4(string, substring, back)
+    simple integer function index4(string, substring, back)
       character(*), intent(in) :: string, substring
       logical, optional, intent(in) :: back ! not ok
     end

diff  --git a/flang/test/Semantics/null-mold-pure-simple.f90 b/flang/test/Semantics/null-mold-pure-simple.f90
new file mode 100644
index 00000000000000..f3e7b9a93a8458
--- /dev/null
+++ b/flang/test/Semantics/null-mold-pure-simple.f90
@@ -0,0 +1,11 @@
+! RUN: %flang_fc1 -fsyntax-only %s
+
+! Verify that NULL(MOLD=) is PURE and can be used in a PURE procedure
+module null_mold_pure_simple
+  implicit none
+contains
+  pure subroutine reset(p)
+    real, pointer, intent(inout) :: p
+    p => null(p)
+  end subroutine reset
+end module null_mold_pure_simple

diff  --git a/flang/test/Semantics/procinterface01.f90 b/flang/test/Semantics/procinterface01.f90
index 70f4a889d6809f..fecbf593ab6d82 100644
--- a/flang/test/Semantics/procinterface01.f90
+++ b/flang/test/Semantics/procinterface01.f90
@@ -48,7 +48,7 @@ end function tan
  type :: derived1
   !REF: /module1/abstract1
   !DEF: /module1/derived1/p1 NOPASS, POINTER (Function) ProcEntity REAL(4)
-  !DEF: /module1/nested1 PUBLIC, PURE (Function) Subprogram REAL(4)
+  !DEF: /module1/nested1 PUBLIC, SIMPLE (Function) Subprogram REAL(4)
   procedure(abstract1), pointer, nopass :: p1 => nested1
   !REF: /module1/explicit1
   !DEF: /module1/derived1/p2 NOPASS, POINTER (Function) ProcEntity REAL(4)
@@ -81,7 +81,7 @@ end function tan
 
  !REF: /module1/nested1
  !DEF: /module1/nested1/x INTENT(IN) ObjectEntity REAL(4)
- pure real function nested1(x)
+ simple real function nested1(x)
   !REF: /module1/nested1/x
   real, intent(in) :: x
   !DEF: /module1/nested1/nested1 ObjectEntity REAL(4)

diff  --git a/flang/test/Semantics/procinterface02.f90 b/flang/test/Semantics/procinterface02.f90
index 6aa5dc13bd9a50..2acfb8ea8a8364 100644
--- a/flang/test/Semantics/procinterface02.f90
+++ b/flang/test/Semantics/procinterface02.f90
@@ -1,10 +1,10 @@
 ! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
 subroutine foo(A, B, P)
   interface
-    real elemental function foo_elemental(x)
+    simple elemental real function foo_elemental(x)
       real, intent(in) :: x
     end function
-    pure real function foo_pure(x)
+    simple real function foo_simple(x)
       real, intent(in) :: x
     end function
     real function foo_nonelemental(x)
@@ -18,7 +18,7 @@ real function foo_nonelemental(x)
   A = P(B)
   !ERROR: Procedure pointer 'p' associated with incompatible procedure designator 'foo_elemental': incompatible procedure attributes: Elemental
   P => foo_elemental
-  P => foo_pure ! ok
+  P => foo_simple ! ok
   !ERROR: PURE procedure pointer 'p' may not be associated with non-PURE procedure designator 'foo_nonelemental'
   P => foo_nonelemental
 end subroutine

diff  --git a/flang/test/Semantics/simple-intrinsic-functions.f90 b/flang/test/Semantics/simple-intrinsic-functions.f90
new file mode 100644
index 00000000000000..f00ea7c714a1e8
--- /dev/null
+++ b/flang/test/Semantics/simple-intrinsic-functions.f90
@@ -0,0 +1,47 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Intrinsic functions are SIMPLE (F2023 16.1 p2). A simple target or actual
+! may be associated with a pointer or dummy that is merely PURE, but a pointer
+! or dummy whose interface is an intrinsic function is SIMPLE and so cannot be
+! associated with a procedure that is only PURE (F2023 10.2.2.4 p3,
+! F2023 15.5.2.10 p1).
+module simple_intrinsic_function
+  implicit none
+  abstract interface
+    simple real function simple_ifc(x)
+      real, intent(in) :: x
+    end function
+    pure real function pure_ifc(x)
+      real, intent(in) :: x
+    end function
+  end interface
+contains
+  pure real function pure_fn(x)
+    real, intent(in) :: x
+    pure_fn = x
+  end function
+  simple real function simple_fn(x)
+    real, intent(in) :: x
+    simple_fn = x
+  end function
+  subroutine take_pure(f)
+    procedure(pure_ifc) :: f
+  end subroutine
+  subroutine take_intrinsic(f)
+    procedure(sqrt) :: f
+  end subroutine
+  subroutine test()
+    procedure(simple_ifc), pointer :: sp
+    procedure(pure_ifc), pointer :: pp
+    procedure(sqrt), pointer :: ip
+    intrinsic :: sin
+    sp => sin
+    pp => sin
+    call take_pure(sin)
+    ip => simple_fn
+    call take_intrinsic(simple_fn)
+    !ERROR: Procedure pointer 'ip' associated with incompatible procedure designator 'pure_fn': incompatible procedure attributes: Simple
+    ip => pure_fn
+    !ERROR: Actual procedure argument has interface incompatible with dummy argument 'f=': incompatible procedure attributes: Simple
+    call take_intrinsic(pure_fn)
+  end subroutine
+end module


        


More information about the flang-commits mailing list