[flang-commits] [flang] 1493ae5 - [flang] Allow missing space in some free-form keywords (#177254)

via flang-commits flang-commits at lists.llvm.org
Thu Jan 22 07:33:40 PST 2026


Author: Peter Klausler
Date: 2026-01-22T07:33:36-08:00
New Revision: 1493ae5da2b8d445fa195142babb000ba99937d8

URL: https://github.com/llvm/llvm-project/commit/1493ae5da2b8d445fa195142babb000ba99937d8
DIFF: https://github.com/llvm/llvm-project/commit/1493ae5da2b8d445fa195142babb000ba99937d8.diff

LOG: [flang] Allow missing space in some free-form keywords (#177254)

When asked to emit warnings about missing spaces in free form source
code, flang-new is emitting some warnings in cases when the space is an
optional one between keywords. Use the existing token matching
capability that allows these ("END " with a trailing blank), add a test
for all cases in Table 6.2, and fix a couple other bogus warning exposed
by compiling that test with -pedantic.

Fixes https://github.com/llvm/llvm-project/issues/177098.

Added: 
    flang/test/Parser/keyword-optional-spaces.f90

Modified: 
    flang/lib/Parser/message.cpp
    flang/lib/Parser/program-parsers.cpp
    flang/lib/Semantics/check-coarray.cpp
    flang/lib/Semantics/resolve-names.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp
index cc4ff9a93c7e0..d68489a192081 100644
--- a/flang/lib/Parser/message.cpp
+++ b/flang/lib/Parser/message.cpp
@@ -98,6 +98,10 @@ std::string MessageExpectedText::ToString() const {
   return common::visit(
       common::visitors{
           [](CharBlock cb) {
+            if (!cb.empty() && cb.back() == ' ') {
+              // Omit any trailing blank in the expected token string.
+              cb = CharBlock{cb.begin(), cb.size() - 1};
+            }
             return MessageFormattedText("expected '%s'"_err_en_US, cb)
                 .MoveString();
           },

diff  --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index 357bee0ad417d..dac377c29d9db 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -256,7 +256,7 @@ TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
 // R1403 end-program-stmt -> END [PROGRAM [program-name]]
 TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
     construct<EndProgramStmt>(
-        recovery("END" >> defaulted("PROGRAM" >> maybe(name)) / atEndOfStmt,
+        recovery("END " >> defaulted("PROGRAM" >> maybe(name)) / atEndOfStmt,
             progUnitEndStmtErrorRecovery)))
 
 // R1404 module ->
@@ -274,7 +274,7 @@ TYPE_CONTEXT_PARSER(
 // R1406 end-module-stmt -> END [MODULE [module-name]]
 TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
     construct<EndModuleStmt>(
-        recovery("END" >> defaulted("MODULE" >> maybe(name)) / atEndOfStmt,
+        recovery("END " >> defaulted("MODULE" >> maybe(name)) / atEndOfStmt,
             progUnitEndStmtErrorRecovery)))
 
 // R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
@@ -342,7 +342,7 @@ TYPE_PARSER(construct<ParentIdentifier>(name, maybe(":" >> name)))
 // R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
 TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
     construct<EndSubmoduleStmt>(
-        recovery("END" >> defaulted("SUBMODULE" >> maybe(name)) / atEndOfStmt,
+        recovery("END " >> defaulted("SUBMODULE" >> maybe(name)) / atEndOfStmt,
             progUnitEndStmtErrorRecovery)))
 
 // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
@@ -358,7 +358,7 @@ TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
 // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
 TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
     construct<EndBlockDataStmt>(
-        recovery("END" >> defaulted("BLOCK DATA" >> maybe(name)) / atEndOfStmt,
+        recovery("END " >> defaulted("BLOCK DATA" >> maybe(name)) / atEndOfStmt,
             progUnitEndStmtErrorRecovery)))
 
 // R1501 interface-block ->
@@ -581,7 +581,7 @@ TYPE_PARSER(construct<Suffix>(
 
 // R1533 end-function-stmt -> END [FUNCTION [function-name]]
 TYPE_PARSER(construct<EndFunctionStmt>(
-    recovery("END" >> defaulted("FUNCTION" >> maybe(name)) / atEndOfStmt,
+    recovery("END " >> defaulted("FUNCTION" >> maybe(name)) / atEndOfStmt,
         progUnitEndStmtErrorRecovery)))
 
 // R1534 subroutine-subprogram ->
@@ -609,7 +609,7 @@ TYPE_PARSER(construct<DummyArg>(name) || construct<DummyArg>(star))
 
 // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
 TYPE_PARSER(construct<EndSubroutineStmt>(
-    recovery("END" >> defaulted("SUBROUTINE" >> maybe(name)) / atEndOfStmt,
+    recovery("END " >> defaulted("SUBROUTINE" >> maybe(name)) / atEndOfStmt,
         progUnitEndStmtErrorRecovery)))
 
 // R1538 separate-module-subprogram ->
@@ -627,7 +627,7 @@ TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
 // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
 TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
     construct<EndMpSubprogramStmt>(
-        recovery("END" >> defaulted("PROCEDURE" >> maybe(name)) / atEndOfStmt,
+        recovery("END " >> defaulted("PROCEDURE" >> maybe(name)) / atEndOfStmt,
             progUnitEndStmtErrorRecovery)))
 
 // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]

diff  --git a/flang/lib/Semantics/check-coarray.cpp b/flang/lib/Semantics/check-coarray.cpp
index 91133693ff614..74e2d4e25c7ec 100644
--- a/flang/lib/Semantics/check-coarray.cpp
+++ b/flang/lib/Semantics/check-coarray.cpp
@@ -100,6 +100,7 @@ template <typename T>
 static void CheckTeamType(
     SemanticsContext &context, const T &x, bool mustBeVariable = false) {
   if (const auto *expr{GetExpr(context, x)}) {
+    NoteUsedSymbols(context, *expr);
     if (!IsTeamType(evaluate::GetDerivedTypeSpec(expr->GetType()))) {
       context.Say(parser::FindSourceLocation(x), // C1114
           "Team value must be of type TEAM_TYPE from module ISO_FORTRAN_ENV"_err_en_US);

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 9919fc248e260..057fa1db239c1 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10161,12 +10161,14 @@ void ResolveNamesVisitor::Post(const parser::AssignStmt &x) {
   if (auto *name{ResolveName(std::get<parser::Name>(x.t))}) {
     CheckEntryDummyUse(name->source, name->symbol);
     ConvertToObjectEntity(DEREF(name->symbol));
+    context().NoteDefinedSymbol(*name->symbol);
   }
 }
 void ResolveNamesVisitor::Post(const parser::AssignedGotoStmt &x) {
   if (auto *name{ResolveName(std::get<parser::Name>(x.t))}) {
     CheckEntryDummyUse(name->source, name->symbol);
     ConvertToObjectEntity(DEREF(name->symbol));
+    context().NoteUsedSymbol(*name->symbol);
   }
 }
 

diff  --git a/flang/test/Parser/keyword-optional-spaces.f90 b/flang/test/Parser/keyword-optional-spaces.f90
new file mode 100644
index 0000000000000..09e96665eb974
--- /dev/null
+++ b/flang/test/Parser/keyword-optional-spaces.f90
@@ -0,0 +1,156 @@
+!RUN: %python %S/../Semantics/test_errors.py %s %flang_fc1 -pedantic -Werror
+blockdata
+endblockdata
+block data
+end blockdata
+block data
+endblock data
+
+subroutine one(p)
+  doubleprecision d1
+  double precision d2
+  enum, bind(c)
+    enumerator :: e1=1
+  endenum
+  enum, bind(c)
+    enumerator :: e2=2
+  end enum
+  class(*), pointer :: p
+  integer assigned
+
+  d1 = 0.
+  d2 = 0.
+  associate(s=>d1)
+  endassociate
+  associate(s=>d2)
+  end associate
+  block
+  endblock
+  block
+  end block
+  critical
+  endcritical
+  critical
+  end critical
+  do
+  enddo
+  do
+  end do
+  endfile(1)
+  end file(1)
+  if (.false.) then
+  elseif (.false.) then
+  else if (.false.) then
+  endif
+  if (.false.) then
+  end if
+  where ([.false.])
+  elsewhere ([.false.])
+  else where ([.false.])
+  endwhere
+  where ([.false.])
+  end where
+  forall(j=1:2)
+  endforall
+  forall(j=1:2)
+  end forall
+  selectcase(1)
+  case(1)
+  endselect
+  select case(1)
+  case(1)
+  end select
+  selecttype(p)
+  type is(doubleprecision)
+  endselect
+  select type(p)
+  type is(double precision)
+  end select
+  !PORTABILITY: deprecated usage
+  assign 10 to assigned
+  goto 10
+10 go to 20
+  !PORTABILITY: deprecated usage
+20 goto assigned
+  !PORTABILITY: deprecated usage
+  go to assigned
+endsubroutine
+
+subroutine two(x,y)
+  use iso_fortran_env, only: team_type
+  real, intent(inout) :: x
+  real, intent(in out) :: y
+  type(team_type) t
+  change team(t)
+  endteam
+  change team(t)
+  end team
+end subroutine
+subroutine three
+endsubroutine three
+subroutine four
+end subroutine four
+
+function f1()
+  f1 = 0.
+endfunction
+function f2()
+  f2 = 0.
+end function
+function f3()
+  f3 = 0.
+endfunction f3
+function f4()
+  f4 = 0.
+end function f4
+module m1
+  interface
+    module subroutine p1
+    endsubroutine
+    module subroutine p2
+    end subroutine
+    module subroutine p3
+    endsubroutine p3
+    module subroutine p4
+    end subroutine p4
+  endinterface
+  interface
+  end interface
+  interface g1
+  endinterface g1
+  interface g2
+  end interface g2
+endmodule
+module m2
+end module
+module m3
+endmodule m3
+module m4
+end module m4
+submodule(m1) sm1
+ contains
+  module procedure p1
+  endprocedure
+endsubmodule
+submodule(m1) sm2
+ contains
+  module procedure p2
+  end procedure
+end submodule
+submodule(m1) sm3
+ contains
+  module procedure p3
+  endprocedure p3
+endsubmodule sm3
+submodule(m1) sm4
+ contains
+  module procedure p4
+  end procedure p4
+end submodule sm4
+
+program p
+  !PORTABILITY: missing space
+  realprogrammersusefortran
+  !PORTABILITY: missing space
+  commonprogrammersusefortran
+endprogram p


        


More information about the flang-commits mailing list