[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