[flang-commits] [flang] [Flang] Add `INLINEALWAYS` Compiler Directive (PR #192674)

Jack Styles via flang-commits flang-commits at lists.llvm.org
Mon Apr 20 03:13:47 PDT 2026


https://github.com/Stylie777 updated https://github.com/llvm/llvm-project/pull/192674

>From a76b05fe5cfb8eea5bda7f79fa997e3dbe552d1d Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Wed, 1 Apr 2026 16:34:19 +0100
Subject: [PATCH 1/4] [Flang] Add `INLINEALWAYS` Compiler Directive

Adds support for the INLINEALWAYS Compiler Directive to Flang. This
was previously supported in Classic-Flang, and works in the same way
as FORCEINLINE.

It can either be defined at the call site, or within the function the
user wishes to inline.

The missing support was highlighted while building an opensource
benchmark, as build warnings were indicating that this compiler
directive was being ignored.
---
 flang/include/flang/Parser/dump-parse-tree.h  |  1 +
 flang/include/flang/Parser/parse-tree.h       |  7 ++-
 flang/lib/Lower/Bridge.cpp                    | 27 +++++++++
 flang/lib/Parser/Fortran-parsers.cpp          |  3 +
 flang/lib/Parser/unparse.cpp                  |  7 +++
 .../lib/Semantics/canonicalize-directives.cpp |  3 +-
 flang/lib/Semantics/resolve-names.cpp         |  3 +-
 flang/test/Lower/inlinealways-directive.f90   | 26 +++++++++
 flang/test/Parser/inlinealways-directive.f90  | 58 +++++++++++++++++++
 9 files changed, 132 insertions(+), 3 deletions(-)
 create mode 100644 flang/test/Lower/inlinealways-directive.f90
 create mode 100644 flang/test/Parser/inlinealways-directive.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index eefab487413da..e13fbefcc8c2e 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -239,6 +239,7 @@ class ParseTreeDumper {
   NODE(CompilerDirective, NoUnroll)
   NODE(CompilerDirective, NoUnrollAndJam)
   NODE(CompilerDirective, Prefetch)
+  NODE(CompilerDirective, InlineAlways)
   NODE(parser, ComplexLiteralConstant)
   NODE(parser, ComplexPart)
   NODE(parser, ComponentArraySpec)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 960ebbcc99efb..bc4f7fd443972 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3344,6 +3344,7 @@ struct StmtFunctionStmt {
 // !DIR$ FORCEINLINE
 // !DIR$ INLINE
 // !DIR$ NOINLINE
+// !DIR$ INLINEALWAYS
 // !DIR$ IVDEP
 // !DIR$ <anything else>
 struct CompilerDirective {
@@ -3380,6 +3381,10 @@ struct CompilerDirective {
     WRAPPER_CLASS_BOILERPLATE(
         Prefetch, std::list<common::Indirection<Designator>>);
   };
+  struct InlineAlways {
+    WRAPPER_CLASS_BOILERPLATE(
+      InlineAlways, std::optional<Name>);
+  };
   EMPTY_CLASS(NoVector);
   EMPTY_CLASS(NoUnroll);
   EMPTY_CLASS(NoUnrollAndJam);
@@ -3392,7 +3397,7 @@ struct CompilerDirective {
   std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
       VectorAlways, VectorLength, std::list<NameValue>, Unroll, UnrollAndJam,
       Unrecognized, NoVector, NoUnroll, NoUnrollAndJam, ForceInline, Inline,
-      NoInline, Prefetch, IVDep>
+      NoInline, InlineAlways, Prefetch, IVDep>
       u;
 };
 
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 28c82a6ca99ce..733e02cd58558 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2083,6 +2083,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
               [&](const Fortran::parser::CompilerDirective::ForceInline &) {
                 stmt.typedCall->setAlwaysInline(true);
               },
+              [&](const Fortran::parser::CompilerDirective::InlineAlways &) {
+                stmt.typedCall->setAlwaysInline(true);
+              },
               [&](const Fortran::parser::CompilerDirective::Inline &) {
                 stmt.typedCall->setInlineHint(true);
               },
@@ -2434,6 +2437,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
                 [&](const Fortran::parser::CompilerDirective::ForceInline &) {
                   callOp.setInlineAttr(fir::FortranInlineEnum::always_inline);
                 },
+                [&](const Fortran::parser::CompilerDirective::InlineAlways &) {
+                  callOp.setInlineAttr(fir::FortranInlineEnum::always_inline);
+                },
                 [&](const auto &) {}},
             dir->u);
       }
@@ -3508,6 +3514,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       e->dirs.push_back(&dir);
   }
 
+  void markCurrentFuncAsAlwaysInline(const Fortran::parser::CompilerDirective::InlineAlways &dir) {
+    mlir::func::FuncOp func = builder->getFunction();
+    if (currentFunctionUnit && !currentFunctionUnit->isMainProgram()) {
+      const std::string symName =
+          currentFunctionUnit->getSubprogramSymbol().name().ToString();
+      if (!llvm::StringRef(dir.v->ToString()).equals_insensitive(symName)) {
+        mlir::emitWarning(toLocation())
+            << "Directive Ignored: INLINEALWAYS directive function name '" << dir.v->ToString()
+            << "' does not match the function '" << symName << "' where this is declared.";
+        return;
+      }
+    }
+    func->setAttr("llvm.always_inline", builder->getUnitAttr());
+  }
+
   void
   attachInliningDirectiveToStmt(const Fortran::parser::CompilerDirective &dir,
                                 Fortran::lower::pft::Evaluation *e) {
@@ -3586,6 +3607,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             [&](const Fortran::parser::CompilerDirective::IVDep &) {
               attachDirectiveToLoop(dir, &eval);
             },
+            [&](const Fortran::parser::CompilerDirective::InlineAlways &inlineAlways) {
+              if (inlineAlways.v.has_value())
+                markCurrentFuncAsAlwaysInline(inlineAlways);
+              else
+                attachInliningDirectiveToStmt(dir, &eval);
+            },
             [&](const auto &) {}},
         dir.u);
   }
diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index b67475074217c..bba8adae42950 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -1339,6 +1339,8 @@ constexpr auto forceinlineDir{
     "FORCEINLINE" >> construct<CompilerDirective::ForceInline>()};
 constexpr auto noinlineDir{
     "NOINLINE" >> construct<CompilerDirective::NoInline>()};
+constexpr auto inlinealwaysDir{
+    "INLINEALWAYS" >> construct<CompilerDirective::InlineAlways>(maybe(name))};
 constexpr auto inlineDir{"INLINE" >> construct<CompilerDirective::Inline>()};
 constexpr auto ivdep{"IVDEP" >> construct<CompilerDirective::IVDep>()};
 TYPE_PARSER(beginDirective >> some(letter) >> "$ "_tok >>
@@ -1355,6 +1357,7 @@ TYPE_PARSER(beginDirective >> some(letter) >> "$ "_tok >>
                 construct<CompilerDirective>(nounroll) ||
                 construct<CompilerDirective>(noinlineDir) ||
                 construct<CompilerDirective>(forceinlineDir) ||
+                construct<CompilerDirective>(inlinealwaysDir) ||
                 construct<CompilerDirective>(inlineDir) ||
                 construct<CompilerDirective>(ivdep) ||
                 construct<CompilerDirective>(
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 5ddd0cfc3a1ef..e9ee0576eb4ad 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1886,6 +1886,13 @@ class UnparseVisitor {
               Word("!DIR$ NOINLINE");
             },
             [&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },
+            [&](const CompilerDirective::InlineAlways &InlineAlways) {
+              Word("!DIR$ INLINEALWAYS");
+              if (InlineAlways.v.has_value()){
+                Word(" ");
+                Word (InlineAlways.v->ToString());
+              }
+            },
             [&](const CompilerDirective::Unrecognized &) {
               Word("!DIR$ ");
               Word(x.source.ToString());
diff --git a/flang/lib/Semantics/canonicalize-directives.cpp b/flang/lib/Semantics/canonicalize-directives.cpp
index f32a3d34c6572..8a1c4d235a666 100644
--- a/flang/lib/Semantics/canonicalize-directives.cpp
+++ b/flang/lib/Semantics/canonicalize-directives.cpp
@@ -66,7 +66,8 @@ static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
       std::holds_alternative<parser::CompilerDirective::ForceInline>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::Inline>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::NoInline>(dir.u) ||
-      std::holds_alternative<parser::CompilerDirective::IVDep>(dir.u);
+      std::holds_alternative<parser::CompilerDirective::IVDep>(dir.u) ||
+      std::holds_alternative<parser::CompilerDirective::InlineAlways>(dir.u);
 }
 
 void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index e1c1167af1604..42556954d7126 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10279,7 +10279,8 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
       std::holds_alternative<parser::CompilerDirective::Inline>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::Prefetch>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::NoInline>(x.u) ||
-      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u)) {
+      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u) ||
+      std::holds_alternative<parser::CompilerDirective::InlineAlways>(x.u)) {
     return;
   }
   if (const auto *tkr{
diff --git a/flang/test/Lower/inlinealways-directive.f90 b/flang/test/Lower/inlinealways-directive.f90
new file mode 100644
index 0000000000000..6ebefbdf4b43c
--- /dev/null
+++ b/flang/test/Lower/inlinealways-directive.f90
@@ -0,0 +1,26 @@
+! Check the appropriate flags are added to inline functions when inlinealways is used
+
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
+
+subroutine test_function()
+  !DIR$ INLINEALWAYS test_function
+end subroutine
+
+subroutine test_function2()
+end subroutine
+
+subroutine test_function3()
+  !DIR$ INLINEALWAYS wrong_func
+end subroutine
+
+subroutine test()
+  !DIR$ INLINEALWAYS
+  call test_function2()
+end subroutine
+
+! CHECK: func.func @_QPtest_function() attributes {llvm.always_inline} {
+! CHECK: fir.call @_QPtest_function2() fastmath<contract> {inline_attr = #fir.inline_attrs<always_inline>} : () -> ()
+
+! CHECK-WARN:      warning: loc({{.*}}inlinealways-directive.f90{{.*}}): Directive Ignored:
+! CHECK-WARN-SAME: INLINEALWAYS directive function name 'wrong_func' does not match the function 'test_function3' where this is declared.
diff --git a/flang/test/Parser/inlinealways-directive.f90 b/flang/test/Parser/inlinealways-directive.f90
new file mode 100644
index 0000000000000..28ec3e7f01aff
--- /dev/null
+++ b/flang/test/Parser/inlinealways-directive.f90
@@ -0,0 +1,58 @@
+! Test that the INLINEALWAYS directive can be parsed, both at callsite and within the function
+
+! RUN: %flang_fc1 -fdebug-dump-parse-tree %s 2>&1 | FileCheck %s --check-prefix=PARSE-TREE
+! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s --check-prefix=UNPARSE
+
+subroutine test_function()
+  !DIR$ INLINEALWAYS test_function
+end subroutine
+
+subroutine test_function2()
+end subroutine
+
+subroutine test()
+  call test_function()
+  !DIR$ INLINEALWAYS
+  call test_function2()
+end subroutine
+
+! UNPARSE: SUBROUTINE test_function
+! UNPARSE:  !DIR$ INLINEALWAYS TEST_FUNCTION
+! UNPARSE: END SUBROUTINE
+! UNPARSE: SUBROUTINE test_function2
+! UNPARSE: END SUBROUTINE
+! UNPARSE: SUBROUTINE test
+! UNPARSE:   CALL test_function()
+! UNPARSE:  !DIR$ INLINEALWAYS
+! UNPARSE:   CALL test_function2()
+! UNPARSE: END SUBROUTINE
+
+! PARSE-TREE: Program -> ProgramUnit -> SubroutineSubprogram
+! PARSE-TREE: | SubroutineStmt
+! PARSE-TREE: | | Name = 'test_function'
+! PARSE-TREE: | SpecificationPart
+! PARSE-TREE: | | ImplicitPart -> 
+! PARSE-TREE: | ExecutionPart -> Block
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> CompilerDirective -> InlineAlways -> Name = 'test_function'
+! PARSE-TREE: | EndSubroutineStmt -> 
+! PARSE-TREE: ProgramUnit -> SubroutineSubprogram
+! PARSE-TREE: | SubroutineStmt
+! PARSE-TREE: | | Name = 'test_function2'
+! PARSE-TREE: | SpecificationPart
+! PARSE-TREE: | | ImplicitPart -> 
+! PARSE-TREE: | ExecutionPart -> Block
+! PARSE-TREE: | EndSubroutineStmt -> 
+! PARSE-TREE: ProgramUnit -> SubroutineSubprogram
+! PARSE-TREE: | SubroutineStmt
+! PARSE-TREE: | | Name = 'test'
+! PARSE-TREE: | SpecificationPart
+! PARSE-TREE: | | ImplicitPart -> 
+! PARSE-TREE: | ExecutionPart -> Block
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> CallStmt = 'CALL test_function()'
+! PARSE-TREE: | | | Call
+! PARSE-TREE: | | | | ProcedureDesignator -> Name = 'test_function'
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> CompilerDirective -> InlineAlways -> 
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> CallStmt = 'CALL test_function2()'
+! PARSE-TREE: | | | Call
+! PARSE-TREE: | | | | ProcedureDesignator -> Name = 'test_function2'
+! PARSE-TREE: | EndSubroutineStmt -> 

>From 6ef1ba69eced86ba3cf9c6c2f16f957666aa63cd Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Fri, 17 Apr 2026 15:50:40 +0100
Subject: [PATCH 2/4] format

---
 flang/include/flang/Parser/parse-tree.h |  3 +--
 flang/lib/Lower/Bridge.cpp              | 11 +++++++----
 flang/lib/Parser/unparse.cpp            |  4 ++--
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index bc4f7fd443972..9c7813122f0d6 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3382,8 +3382,7 @@ struct CompilerDirective {
         Prefetch, std::list<common::Indirection<Designator>>);
   };
   struct InlineAlways {
-    WRAPPER_CLASS_BOILERPLATE(
-      InlineAlways, std::optional<Name>);
+    WRAPPER_CLASS_BOILERPLATE(InlineAlways, std::optional<Name>);
   };
   EMPTY_CLASS(NoVector);
   EMPTY_CLASS(NoUnroll);
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 733e02cd58558..575989e64d11d 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3514,15 +3514,17 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       e->dirs.push_back(&dir);
   }
 
-  void markCurrentFuncAsAlwaysInline(const Fortran::parser::CompilerDirective::InlineAlways &dir) {
+  void markCurrentFuncAsAlwaysInline(
+      const Fortran::parser::CompilerDirective::InlineAlways &dir) {
     mlir::func::FuncOp func = builder->getFunction();
     if (currentFunctionUnit && !currentFunctionUnit->isMainProgram()) {
       const std::string symName =
           currentFunctionUnit->getSubprogramSymbol().name().ToString();
       if (!llvm::StringRef(dir.v->ToString()).equals_insensitive(symName)) {
         mlir::emitWarning(toLocation())
-            << "Directive Ignored: INLINEALWAYS directive function name '" << dir.v->ToString()
-            << "' does not match the function '" << symName << "' where this is declared.";
+            << "Directive Ignored: INLINEALWAYS directive function name '"
+            << dir.v->ToString() << "' does not match the function '" << symName
+            << "' where this is declared.";
         return;
       }
     }
@@ -3607,7 +3609,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             [&](const Fortran::parser::CompilerDirective::IVDep &) {
               attachDirectiveToLoop(dir, &eval);
             },
-            [&](const Fortran::parser::CompilerDirective::InlineAlways &inlineAlways) {
+            [&](const Fortran::parser::CompilerDirective::InlineAlways
+                    &inlineAlways) {
               if (inlineAlways.v.has_value())
                 markCurrentFuncAsAlwaysInline(inlineAlways);
               else
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index e9ee0576eb4ad..21abd7de1c7bb 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1888,9 +1888,9 @@ class UnparseVisitor {
             [&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },
             [&](const CompilerDirective::InlineAlways &InlineAlways) {
               Word("!DIR$ INLINEALWAYS");
-              if (InlineAlways.v.has_value()){
+              if (InlineAlways.v.has_value()) {
                 Word(" ");
-                Word (InlineAlways.v->ToString());
+                Word(InlineAlways.v->ToString());
               }
             },
             [&](const CompilerDirective::Unrecognized &) {

>From 70d068b2867cd4b3b486f99889512bfb1e855f17 Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Fri, 17 Apr 2026 16:20:32 +0100
Subject: [PATCH 3/4] Add Directives.md entry

---
 flang/docs/Directives.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 1654a9b2623f2..8f487f3e15898 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -99,6 +99,16 @@ A list of non-standard directives supported by Flang
   assignment statement.
 * `!dir$ forceinline` works in the same way as the `inline` directive, but it forces
    inlining by the compiler on a function call statement.
+* `!dir$ inlinealways <name>`. An alternative spelling to `forceinline`, providing compatibility
+  with older Fortran compilers, such as classic-flang. Can be defined at the callsite, or
+  in the function you want to inline. `name` is optional and should only be used when
+  defining the directive within a function, example:
+  ```
+  function test
+    !DIR$ INLINEALWAYS test
+    ...
+  end function
+  ```
 * `!dir$ noinline` works in the same way as the `inline` directive, but prevents
   any attempt of inlining by the compiler on a function call statement.
 

>From 84220ac249138de6457b42c0493b5153caa03844 Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Mon, 20 Apr 2026 11:06:52 +0100
Subject: [PATCH 4/4] Respond to review comments

---
 flang/docs/Directives.md                       |  4 ++--
 flang/lib/Lower/Bridge.cpp                     |  9 ++-------
 flang/lib/Semantics/resolve-names.cpp          | 18 ++++++++++++++++--
 flang/test/Lower/inlinealways-directive.f90    | 10 +++-------
 .../Semantics/inlinealways-directive01.f90     | 12 ++++++++++++
 5 files changed, 35 insertions(+), 18 deletions(-)
 create mode 100644 flang/test/Semantics/inlinealways-directive01.f90

diff --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 8f487f3e15898..b128acd9273b4 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -100,9 +100,9 @@ A list of non-standard directives supported by Flang
 * `!dir$ forceinline` works in the same way as the `inline` directive, but it forces
    inlining by the compiler on a function call statement.
 * `!dir$ inlinealways <name>`. An alternative spelling to `forceinline`, providing compatibility
-  with older Fortran compilers, such as classic-flang. Can be defined at the callsite, or
+  with older Fortran compilers, such as classic-flang. It can be defined at the callsite, or
   in the function you want to inline. `name` is optional and should only be used when
-  defining the directive within a function, example:
+  specifying the directive within a function, example:
   ```
   function test
     !DIR$ INLINEALWAYS test
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 575989e64d11d..cc9024a87fa40 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3520,15 +3520,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     if (currentFunctionUnit && !currentFunctionUnit->isMainProgram()) {
       const std::string symName =
           currentFunctionUnit->getSubprogramSymbol().name().ToString();
-      if (!llvm::StringRef(dir.v->ToString()).equals_insensitive(symName)) {
-        mlir::emitWarning(toLocation())
-            << "Directive Ignored: INLINEALWAYS directive function name '"
-            << dir.v->ToString() << "' does not match the function '" << symName
-            << "' where this is declared.";
-        return;
+      if (dir.v->ToString() == symName) {
+        func->setAttr("llvm.always_inline", builder->getUnitAttr());
       }
     }
-    func->setAttr("llvm.always_inline", builder->getUnitAttr());
   }
 
   void
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 42556954d7126..4db4edd3b8d50 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10279,8 +10279,7 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
       std::holds_alternative<parser::CompilerDirective::Inline>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::Prefetch>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::NoInline>(x.u) ||
-      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u) ||
-      std::holds_alternative<parser::CompilerDirective::InlineAlways>(x.u)) {
+      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u)) {
     return;
   }
   if (const auto *tkr{
@@ -10372,6 +10371,21 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
         }
       }
     }
+  } else if (const auto *inlineAlways{
+                 std::get_if<parser::CompilerDirective::InlineAlways>(&x.u)}) {
+    if (!inlineAlways->v.has_value()) {
+      return;
+    }
+
+    Symbol *sym{currScope().symbol()};
+    if (!sym || !sym->has<SubprogramDetails>()) {
+      Say(x.source,
+          "!DIR$ INLINEALWAYS directive with name must appear in a subroutine or function"_err_en_US);
+    }
+    if (inlineAlways->v->ToString() != sym->name().ToString()) {
+      context().Warn(common::UsageWarning::IgnoredDirective, x.source,
+          "IGNOREALWAYS function name does not match the function"_warn_en_US);
+    }
   } else if (context().ShouldWarn(common::UsageWarning::IgnoredDirective)) {
     Say(x.source, "Unrecognized compiler directive was ignored"_warn_en_US)
         .set_usageWarning(common::UsageWarning::IgnoredDirective);
diff --git a/flang/test/Lower/inlinealways-directive.f90 b/flang/test/Lower/inlinealways-directive.f90
index 6ebefbdf4b43c..e610eafb2ae9b 100644
--- a/flang/test/Lower/inlinealways-directive.f90
+++ b/flang/test/Lower/inlinealways-directive.f90
@@ -1,11 +1,11 @@
-! Check the appropriate flags are added to inline functions when inlinealways is used
+! Check the appropriate flags are added to inline functions when inlinealways is used, or ignored when the name is incorrect.
 
 ! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -emit-hlfir %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
 
 subroutine test_function()
   !DIR$ INLINEALWAYS test_function
 end subroutine
+! CHECK: func.func @_QPtest_function() attributes {llvm.always_inline} {
 
 subroutine test_function2()
 end subroutine
@@ -13,14 +13,10 @@ subroutine test_function2()
 subroutine test_function3()
   !DIR$ INLINEALWAYS wrong_func
 end subroutine
+! CHECK: func.func @_QPtest_function2() {
 
 subroutine test()
   !DIR$ INLINEALWAYS
   call test_function2()
 end subroutine
-
-! CHECK: func.func @_QPtest_function() attributes {llvm.always_inline} {
 ! CHECK: fir.call @_QPtest_function2() fastmath<contract> {inline_attr = #fir.inline_attrs<always_inline>} : () -> ()
-
-! CHECK-WARN:      warning: loc({{.*}}inlinealways-directive.f90{{.*}}): Directive Ignored:
-! CHECK-WARN-SAME: INLINEALWAYS directive function name 'wrong_func' does not match the function 'test_function3' where this is declared.
diff --git a/flang/test/Semantics/inlinealways-directive01.f90 b/flang/test/Semantics/inlinealways-directive01.f90
new file mode 100644
index 0000000000000..324ed7f5436e1
--- /dev/null
+++ b/flang/test/Semantics/inlinealways-directive01.f90
@@ -0,0 +1,12 @@
+! Check that the appropriate warnings are emitted when using INLINEALWAYS incorrectly
+! RUN: %python %S/test_errors.py %s %flang_fc1
+
+module m
+! ERROR: !DIR$ INLINEALWAYS directive with name must appear in a subroutine or function
+  !DIR$ INLINEALWAYS m
+end module
+
+subroutine test_function3()
+! WARNING: IGNOREALWAYS function name does not match the function [-Wignored-directive]
+  !DIR$ INLINEALWAYS wrong_func
+end subroutine



More information about the flang-commits mailing list